Tony
Tony

Reputation: 2929

Rename file names in current directory and all subdirectories

I have 4 files with the following names in different directories and subdirectories

tag0.txt, tag1.txt, tag2.txt and tag3.txt 

and wish to rename them as tag0a.txt, tag1a.txt ,tag2a.txt and tag3a.txt in all directories and subdirectories.

Could anyone help me out using a shell script?

Cheers

Upvotes: 1

Views: 3939

Answers (5)

Dennis Williamson
Dennis Williamson

Reputation: 360693

Using the Perl script version of rename that may be on your system:

find . -name 'tag?.txt' -exec rename 's/\.txt$/a$&/' {} \;

Using the binary executable version of rename:

find . -name 'tag?.txt' -exec rename .txt a.txt {} \;

which changes the first occurrence of ".txt". Since the file names are constrained by the -name argument, that won't be a problem.

Upvotes: 1

sorpigal
sorpigal

Reputation: 26116

This can of course be done with find:

find . -name 'tag?.txt' -type f -exec bash -c 'mv "$1" ${1%.*}a.${1##*.}' -- {} \;

Upvotes: 3

marco
marco

Reputation: 4675

Here is a posix shell script (checked with dash):

visitDir() {
    local file
    for file in "$1"/*; do
            if [ -d "$file" ]; then
                    visitDir "$file";
            else
                    if [ -f "$file" ] && echo "$file"|grep -q '^.*/tag[0-3]\.txt$'; then
                            newfile=$(echo $file | sed 's/\.txt/a.txt/')
                            echo mv "$file" "$newfile"
                    fi
            fi

    done
}

visitDir .

If you can use bashisms, just replace the inner IF with:

if [[ -f "$file" && "$file" =~ ^.*/tag[0-3]\.txt$ ]]; then
    echo mv "$file" "${file/.txt/a.txt}"
fi

First check that the result is what you expected, then possibly remove the "echo" in front of the mv command.

Upvotes: 1

l0b0
l0b0

Reputation: 58988

$ shopt -s globstar
$ rename -n 's/\.txt$/a\.txt/' **/*.txt
foo/bar/tag2.txt renamed as foo/bar/tag2a.txt
foo/tag1.txt renamed as foo/tag1a.txt
tag0.txt renamed as tag0a.txt

Remove -n to rename after checking the result - It is the "dry run" option.

Upvotes: 3

jcomeau_ictx
jcomeau_ictx

Reputation: 38492

Is this good enough?


jcomeau@intrepid:/tmp$ find . -name tag?.txt
./a/tag0.txt
./b/tagb.txt
./c/tag1.txt
./c/d/tag3.txt
jcomeau@intrepid:/tmp$ for txtfile in $(find . -name 'tag?.txt'); do \
 mv $txtfile ${txtfile%%.txt}a.txt; done
jcomeau@intrepid:/tmp$ find . -name tag*.txt
./a/tag0a.txt
./b/tagba.txt
./c/d/tag3a.txt
./c/tag1a.txt

Don't actually put the backslash into the command, and if you do, expect a '>' prompt on the next line. I didn't put that into the output to avoid confusion, but I didn't want anybody to have to scroll either.

Upvotes: 0

Related Questions