As other answers have already identified, ${f%.*}
is expanded by the shell before it runs the xargs
command. You need this expansion to happen once for each file name, with the shell variable f
set to the file name (passing -I f
doesn't do that: xargs
has no notion of shell variable, it looks for the string f
in the command, so if you'd used e.g. xargs -I e echo …
it would have executed commands like ./somedir/somefile.wmacho .mp3
).
Keeping on this approach, tell xargs
to invoke a shell that can perform the expansion. Better, tell find
— xargs
is a largely obsolete tool and is hard to use correctly, as modern versions of find have a construct that does the same job (and more) with fewer plumbing difficulties. Instead of find … -print0 | xargs -0 command …
, run find … -exec command … {} +
.
find . -name '*.wma' -type f -exec sh -c 'for f; do echo "${f%.*}.mp3"; done' _ {} +
The argument _
is $0
in the shell; the file names are passed as the positional arguments which for f; do …
loops over. A simpler version of this command executes a separate shell for each file, which is equivalent but slightly slower:
find . -name '*.wma' -type f -exec sh -c 'echo "${0%.*}.mp3"' {} \;
You don't actually need to use find
here, assuming you're running a reasonably recent shell (ksh93, bash ≥4.0, or zsh). In bash, put shopt -s globstar
in your .bashrc
to activate the **/
glob pattern to recurse in subdirectories (in ksh, that's set -o globstar
). Then you can run
for f in **/*.wma; do
echo "${f%.*}.mp3"
done
(If you have directories called *.wma
, add [ -f "$f" ] || continue
at the beginning of the loop.)
Taking advantage of GNU mv
's -t
option to specify the target directory, instead of relying on the last argument:
find . -name "*" -maxdepth 1 -exec mv -t /home/foo2/bulk2 {} +
If you were on a system without the option, you could use an intermediate shell to get the arguments in the right order (find … -exec … +
doesn't support putting extra arguments after the list of files).
find . -name "*" -maxdepth 1 -exec sh -c 'mv "$@" "$0"' /home/foo2/bulk2 {} +
Best Answer
Loop over the pdf files, use parameter expansion to extract the basename:
Update: I got the logic backwards, should be fixed now.