Example of usage (contrived!开发者_运维百科): rename .mp3 files to .txt.
I'd like to be able to do something like
find -name '*.mp3' -print0 | xargs -0 -I'file' mv file ${file%.mp3}.txt
This doesn't work, so I've resorted to piping find
's output through sed -e 's/.mp3//g'
, which does the trick.
Seems a bit hackish though; is there a way to use the usual bash ${x%y}
syntax?
No, xargs -0 -I'file' mv file ${file%.mp3}.txt
will not work because the file
variable will be expanded by the xargs program and not the shell. Actually it is not quite correct to refer to it as a variable, it is called "replace-str" in the manual of xargs.
Update: To just use xargs and bash (and no sed or similar) you can of course let xargs start a bash process which then can do whatever substitution you want:
find -name '*.mp3' -print0 | xargs -0 bash -c \
'while [ -n "$1" ]; do mv "$1" "${1%.mp3}.txt" ; shift; done;' "bash"
If you have GNU Parallel installed:
find -name '*.mp3' -print0 | parallel -0 mv {} {.}.txt
If your file names do not contain \n (newline) this will work too:
find -name '*.mp3' | parallel mv {} {.}.txt
Watch the intro video to learn more about GNU Parallel http://www.youtube.com/watch?v=OpaiGYxkSuQ
Just to add another suggestion, even though it doesn't use the shell's substitution mechanism, but instead, sed's.
find -name '*.mp3' -print |
sed -e 's/\.mp3$//' -e "s/.*/mv '&\.mp3' '&\.txt'/" |
sh
In other words, create an mv
command line for each file name, and pass the result to sh
.
This will fail if any of the files have an apostrophe (single quote) in their file name. I mainly post this to counter the "if all you have is xargs, every problem will look like a nail" syndrome.
Not all seds have exactly the same syntax. In particular, I'm not 100% sure you can have multiple -e arguments on some crufty old SunOS (look for the XPG-compatible sed in something like /usr/ucb/blah/barf/vomit/xpg4/bin/sed
)
find . -type f -name '*.mp3' | while read -r F
do
mv "$F" "${F%.mp3}.txt"
done
Bash 4+
shopt -s globstar
shopt -s nullglob
for file in **/*.mp3
do
mv "$file" "${file%.mp3}.txt"
done
perl rename.pl 's/\.mp3$/.txt/' *.mp3
# Or **/*.mp3 for zsh and bash with specific settings set, for a recursive
# rename.
http://people.sc.fsu.edu/~jburkardt/pl_src/rename/rename.html
精彩评论