0

Very new to scripting. I have a directory containing some text files and some with text files that also contain an additional extension (.xfr) e.g. file1.txt, file2.txt.xfr, file3.txt, file4.txt.xfr.

Trying to write a bash script to check the directory, rename the file if it contains the .xfr (removing the extension) and then write out log entries depending on the outcome.

I'm able to write a script to rename files but when it comes to the if part, I'm struggling. Here is the bit that works:

#!/bin/bash

for file in ~/Test/Files/*.xfr
do
    mv "$file" "${file%.xfr}"
    echo "$file has been resent" > ~/Test/log.txt
done

To add the if, I thought this would work but sadly not:

#!/bin/bash

if [[ ! -e ~/Test/Files/*.xfr ]]
then
    mv "$file" "${file%.xfr}"
    echo "$file has been renamed" > ~/Test/log.txt
else 
    echo "no files were renamed" ~/Test/log.txt
fi

Any assistance would be greatly appreciated.

1

Modifying your first script a tiny bit:

#!/bin/bash

for file in ~/Test/Files/*.xfr
do
    if [ ! -e "$file" ]; then
        echo 'no files were renamed'
        break
    fi

    mv "$file" "${file%.xfr}"
    echo "$file has been renamed" 
done > ~/Test/log.txt

I've done two things here:

  1. The redirection to the log file would truncate the log file in each iteration, so I've moved it to the end of done instead so that it redirects all standard output of the loop.

  2. If the pattern does not match any filenames, it will remain unexpanded by default. I detect this with a -e test and output a special message. Then I break out of the loop.

Alternative:

#!/bin/bash

for file in "$HOME/Test/Files"/*.xfr
do
    if [ -e "$file" ]; then
        mv "$file" "${file%.xfr}"
        printf '%s has been renamed\n' "$file"
    else
        echo 'no files were renamed'
    fi   
done >"$HOME/Test/log.txt"

Here I've just changed the flow a bit and used $HOME in place of tilde (looks nicer in a script IMHO). I'm also using printf instead of echo as it's generally safer for outputting variable data (see e.g. "Why is printf better than echo?").

Both alternatives above may also run with /bin/sh rather than /bin/bash.

Another alternative, if you want to write more of a "report":

#!/bin/bash

shopt -s nullglob

xfr_files=( "$HOME/Test/Files"/*.xfr )

for file in "${xfr_files[@]}"; do
    mv "$file" "${file%.xfr}"
done

printf '%d files renamed\n' "${#xfr_files[@]}"
if [ "${#xfr_files[@]}" -gt 0 ]; then
    printf '\t%s\n' "${xfr_files[@]}"
fi

This sets the nullglob shell option in bash which makes patterns expand to nothing if there are no matches. It then writes out the number of files renamed and if this number is greater than zero, it also lists the filenames with a tab indent.

  • why don't use mv -v instead of echo ? – Alexander Jan 11 at 12:44
  • @Alexander Two reasons: 1) I prefer writing solutions that are portable (-v is a non-standard option for mv), and 2) The user may want to output a custom text for each file, as they do in the question. – Kusalananda Jan 11 at 12:48

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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