我想评估basename
给定参数的表达式xargs
。
我测试过:
find . -name '*.txt' | xargs -I f cp f DIR_OUT/copied_$(basename f)
这是no file or directory
因为$(basename f)
没有正确评估。
我可以将其分为两个步骤:复制和更改文件名,但我想学习如何使用xargs
.
答案1
在命令启动之前,您在命令中使用的命令替换$(basename f)
将仅被评估一次(产生字符串f
) 。xargs
这就是您的代码无法将文件复制到正确名称的原因。
您收到的“没有这样的文件或目录”错误是由于f
inDIR_OUT/copied_f
被替换为 找到的文件的路径名find
。
做同样事情的更稳健的方法,
find . -type f -name '*.txt' -exec sh -c '
for pathname do
cp "$pathname" "DIR_OUT/copied_${pathname##*/}"
done' sh {} +
或者,xargs
同时注意在find
和之间传递找到的路径名xargs
作为以 null 结尾的字符串:
find . -type f -name '*.txt' -print0 |
xargs -0 sh -c '
for pathname do
cp "$pathname" "DIR_OUT/copied_${pathname##*/}"
done' sh
在这两种变体中,我们调用一个小的内联 shell 脚本,该脚本循环遍历给定的路径名并将它们复制到目录下的新名称DIR_OUT
。可以${pathname##*/}
替换为$( basename "$pathname" )
.
请注意,-print0
(in find
) 和-0
(in xargs
) 是非标准的,但通常实现。
有关的:
答案2
您需要对原始命令进行一些小修改
find . -name '*.txt' | xargs -I f sh -c 'cp f DIR_OUT/copied_$(basename f)'
答案3
要解释$()
,您需要从 运行 shell xargs
。
看这里
您还应该使用 find 的空分隔输出(当系统允许时),以防止文件名中出现有问题的字符。
这应该做你想要的:(如果某个地方没有空支持,请-0
从 中删除xargs
并替换-print0
为-print
)
find . -type f -name '*.txt' -print0 | xargs -n1 -r0 /bin/sh -c 'cp "$1" "DIR_OUT/copied_$(basename "$1")"' ''
-type f
确保 find 只给出文件结果
-print0
make find 打印 null 终止的输出
-n1
确保xargs
仅将一个结果传递给进程
-r
告诉xargs
如果没有结果则不要运行内容
-0
makexargs
接受 null 终止的输入
运行的命令是一个带有内联脚本和一个空白参数的 shell(因为这就是参数传递给-c
脚本的方式)
xargs
将参数传递给sh -c 'commands' ''
,这会导致第一个参数位于$1
-c 内。单引号阻止调用 shell 处理$()
and $1
。