I want to learn more so I have tried to script more than just using the terminal. I know rename and I can rename image files with rename 's/ /_/g' *.jpg but when I write it in a shell script to point at a directory:


for imgfile in $(find $DIRECTORY -type f -name \*.jpg); do
    echo 'replacing whitespace in' $(basename $imgfile)
    rename -f 's/ /_/g' *.jpg 

it doesn't work and the terminal will take a file (example: 1234 abcd.jpg) and echo abcd.jpg. So where am I going wrong?

  • this doesnt add up... you are looping the result from find and renaming all jpg in that dir on every iteration.
    – user986805
    Oct 27, 2019 at 19:07

2 Answers 2


Spaces in filenames are evil.

I see three problems with the script:

  1. when doing the for... loop, you will have two different values when you find a file with space. i.e., if you have the files "file1 1.jpg" and "file2 2.jpg" and you do:

    for i in $(find . -type f -name \*.jpg); do 
       echo $i

    You'll have


    because the shell breaks the argument at spaces. The output of the $(find ...) command will be

    ./file1 1.jpg 
    ./file2 2.jpg 

    Which are four words for the command for to be assigned at $i --- by default the shell treats spaces and newlines in the same way when expanding.

    You can circumvent this changing the IFS char.

    Your first line could look like:

    IFS=$'\n' find $DIRECTORY -type f -name \*.jpg | while read -r imgfile; do
  2. you are feeding the for loop with a single file name, so you should say:

    rename -f 's/ /_/g' "$imgfile"

    otherwise *.jpg is expanded in the current directory, and not in $DIRECTORY (and note the quotes --- given that $imgfile is going to have spaces in it).

  3. even then, if $DIRECTORY has some path component with spaces in it, the rename will fail (there will be intermediate directories that do not exist).

  4. suggestion (keeping it simple):

    rename -f 's/ /_/g' *.jpg

    doesn't do what you want?

Added: my script (created ages ago, when there was no rename in Unix), is this --- it will remove spaces and tab in all files in current dir that have them in the name:

ls -1  | grep -E " |\t" | while read i; do
    a=`echo $i | tr " \t" "__"`
    mv -v "$i" $a

Added++: this link I found researching this answer is excellent.


Best way to parse the result from find is by null terminate the output with -print0


while IFS= read -d '' -r; do
    rename -f "s/ /_/g" "$REPLY"
    if [[ ! -f $REPLY ]]; then
        echo "Renaming file: $(basename "$REPLY")"
done < <(find -type f -name '*.jpg' -print0)

(You can manage without a loop).

$ find -type f -name '*.jpg' \
    -exec bash -c 'rename -f "s/ /_/g" "$1"; \
    [[ -f $1 ]] || echo "Renaming file: $(basename "$1")"' _ '{}' \;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.