I want to insert an integer into filenames with various extensions in multiple subdirectories using bash.
Examples:
./trial2/foo.hhh
--> ./trial2/foo1.hhh
./trial2/trial3/foo.txt
--> ./trial2/trial3/foo1.txt
I tried to separate the filename from the extension and insert the integer in between with:
i=123
find . -type f -exec sh -c ' echo mv "$0" "${0%.*}${i}.${0##*.}" ' {} \;
mv ./trial2/foo.hhh ./trial2/foo.hhh
But the variable output ${i}
is not printed. Why?
If I change to:
find . -type f -exec sh -c ' mv "$0" "${0%.*}123.${0##*.}" ' {} \;
mv ./trial2/foo.hhh ./trial2/foo123.hhh
The number is printed. However, I need the variable ${i}
as it will be defined in a wrapping for-loop.
You are almost there; you just hit a quoting subtlety. i
is declared in the current shell, so needs to be passed into the sh
run by find
somehow. In your current command, ${i}
is in single quotes, so is not interpreted by bash
before the quoted material is passed to sh
.
As suggested by Charles Duffy:
find . -type f -exec sh -c ' echo mv "$0" "${0%.*}${1}.${0##*.}" ' {} "$i" \;
Within the sh
command, $0
is the {}
, as you know. $1
is the second parameter to the sh
, which is "$i"
(i
expanded as a single word). Instead of ${i}
, the sh
command uses ${1}
to access that parameter (a copy of i
).
In this example, i
is interpolated in the current shell.
Before: find . -type f -exec sh -c ' echo mv "$0" "${0%.*}${i}.${0##*.}" ' {} \;
After: find . -type f -exec sh -c ' echo mv "$0" "${0%.*}'"${i}"'.${0##*.}" ' {} \;
^^ ^^
The '"${i}"'
drops you out of the single quotes, then expands i
, then takes you back into the single quotes. That way the command you are passing to sh
includes the value of i
you want.