Want to make txt files for every png in the folder

You can remove the existing extension using the shell's parameter expansion features

${parameter%pattern} The 'pattern' is matched against the end of 'parameter'. The result is the expanded value of 'parameter' with the shortest match deleted.

So in your case, replace $filePng.txt with "${filePng%.png}.txt"


You can use the basename command here:

touch "$folder/$(basename "$filePng" .png).txt"

Note the additional $folder/. This is neccessary since the basename command removes the path from.


With variation on what steeldriver already mentioned - parameter expansion - we can use string replacement to do the job. Additionally, you should quote variables. Below is your edited script.

#!/bin/bash

folder='/home/data/mnist/training'

for filePng in "$folder"/*
do
    touch "${filePng/.png/.txt}"
done

If you have a lot of files to create it would be worthwhile to “touch” more than one file at a time, so that you don't need to fork a new process for each of them (which takes quite some time if performed multiple thousand times).

Option 1: pattern substitution + xargs

This option will supply multiple paths to the touch command at once, usually a few thousand or whatever the system can fit on a single command line.

find "$folder" -mindepth 1 -maxdepth 1 -name '*.png' -print0 |
sed -ze 's/\.png$/.txt/' |
xargs -r0 -- touch --

Option 2: parameter expansion + command output redirection

This option doesn't run touch at all but uses Bash/Bourne/POSIX shell features instead which don't require sub-processes at all.

for f in "$folder"/*.png; do
    : >> "${f%.png}.txt"
done

If you're confident that you don't have files with .png somewhere in the middle of the name, then you can just use an array with parameter expansion:

pngs=( /path/to/pngs/*.png )
touch "${pngs[@]/.png/.txt}"

This stores all the paths to the files ending in .png in an array and then uses parameter expansion to create the list of .txt files, by substituting .png for .txt on each one.

Bear in mind that this will break if you have so many files that they cannot all be passed as arguments to the same invocation of touch.