The $(basename f)
command substitution that you use in your command would be evaluated exactly once (yielding the string f
), before the xargs
command is even started. This is why your code fails to copy the files to the correct names.
The "No such file or directory" error that you get is due to the f
in DIR_OUT/copied_f
being replaced by the pathnames of the files found by find
.
A more robust way of doing the same thing,
find . -type f -name '*.txt' -exec sh -c '
for pathname do
cp "$pathname" "DIR_OUT/copied_${pathname##*/}"
done' sh {} +
Or, with xargs
while taking care to pass the found pathnames between find
and xargs
as nul-terminated strings:
find . -type f -name '*.txt' -print0 |
xargs -0 sh -c '
for pathname do
cp "$pathname" "DIR_OUT/copied_${pathname##*/}"
done' sh
In both of these variations, we call a small in-line shell script that loops over the given pathnames and copies them to new names under the directory DIR_OUT
. The ${pathname##*/}
may be replaced by $( basename "$pathname" )
.
Note that -print0
(in find
) and -0
(in xargs
) are non-standard, but commonly implemented.
Related:
$()
, evaluates it, (resulting inf
), start up thefind
andxargs
with the resulting parameters. Quoting is needed to prevent that... Butxargs
is not a shell and does not understand things like$()
on its own... – Gert van den Berg Jun 13 '19 at 06:37