Reputation: 2689
I can use the for
command to change .dat files to .txt files like this
for f in *.dat
do
mv $f ${f/.dat/.txt}
done
where ${f/.dat/.txt}
modifies the .dat
in each filename to .txt
. But how can I do this with find
? An attempt to use {}
as a variable fails.
find . -type f -exec echo ${} \;
-bash: ${}: bad substitution
I can get further by assigning {}
to a parameter like this
find . -type f -name '*.dat' -exec echo `f={}; echo $f` \;
but an attempt at substitution fails
find . -type f -name '*.dat' -exec echo `f={}; echo $(echo ${f/.dat/.txt})` \;
prints
./file1.dat
./file2.dat
not
./file1.txt
./file2.txt
Does anyone know how to make find
behave the way I want it?
Upvotes: 1
Views: 140
Reputation: 2689
This post from @celada about systemd
points to the solution. The -exec
in find
does not invoke a shell, so although some parameter manipulation is supported, parameter expansion like $f{/.dat/.txt}
isn't.
So the trick is to exec a shell and then escape the dollar signs like this
find . -type f -name '*.dat' -exec sh -c "f={}; mv \$f \${f/dat/txt}" \;
Upvotes: 2
Reputation: 42710
You could just skip the exec
parameter and echo the output to sed instead:
find . -type f -name '*.dat' | sed 's/.dat/.txt/'
Upvotes: 0
Reputation: 37298
You can use awk
to modify filename and generate cmds that you pass to bash, i.e.
cat fixer.awk
#!/bin/awk -f
{
outFile=$0
sub(/\.txt/, ".dat", outFile) ; print "mv "$0 " " outFile
}
chmod 755 fixer.awk
find . -type f -name '*.dat' | /path/to/fixer.awk
output
mv 34274841/file1.txt 34274841/file1.dat
mv 34274841/file2.txt 34274841/file2.dat
When you're happy with that output, and certain there are no unforeseen consequences ;-) , then execute
find . -type f -name '*.dat' | /path/to/fixer.awk | bash
IHTH
Upvotes: 1