我遇到了以下问题:
user@machine:/$ echo ./dir/fil | xargs -I {} bash -c "echo $(basename {})"
./dir/fil
为什么不只是打印fil
?
因此basename
似乎获得了预期的参数./dir/fil
,但不知何故假设它是整个文件名。相反,当与dirname
它一起使用时,只会打印出.
。感觉好像/
s 以某种方式被转义了。
我为何关心?
我实际上需要运行这样的操作:
find -name "*.foo" | xargs -I {} bash -c "cd $(dirname \"{}\"); thirdpartytool $(basename \"{}\") 2>&1 > /dev/null | sort"
- 如果任何调用返回一个非零的返回代码,我需要一个非零的返回代码
thirdpartytool
,所以find ... -exec ...
对我来说不起作用。 - 我需要输出重定向(丢弃 stdout 并对 stderr 进行排序)所以我需要调用另一个 shell。
- 我需要
cd
因为thirdpartytool
必须从文件所在的目录调用,所以我需要dirname
并且basename
在子shell中。
答案1
echo ./dir/fil | xargs -I {} bash -c "echo $(basename {})"
这里$(basename {})
是双引号,因此xargs
它在运行之前就被当前 shell 扩展了。 的输出basename {}
是{}
,因此命令变成:
echo ./dir/fil | xargs -I {} bash -c "echo {}"
如果你用单引号括住 shell 代码,情况就会有所不同。嵌入{}
shell 代码是错误的. 您应该将扩展的结果{}
作为位置参数传递。
最终,您要使用find
。真正强大的命令将采用以下形式find … -print0 | xargs -0 …
(如果支持)或find … -exec …
。
如果我理解你的目标正确的话,你的命令将是这样的:
find . -name "*.foo" -print0 \
| xargs -0 -L1 sh -c 'cd "$(dirname "$1")" && thirdpartytool "$(basename "$1")" 2>&1 >/dev/null | sort' sh
在哪里
- 我修正了引用,
- 我确保
thirdpartytool
只有cd
成功后才会运行, - 我使用它是
sh
因为 shell 代码中没有任何特定于 Bash 的内容。
补充笔记:
- 无需致电
dirname
,basename
您可以让 shell 完成这项工作。 - 第二个
sh
解释如下:中的第二个 sh 是什么sh -c 'some shell code' sh
?