将参数从xargs传递到bash作为变量进行处理

时间:2016-03-23 18:49:28

标签: bash xargs

我试图并行运行许多命令,并且需要先对输入进行一些字符串操作。如何使以下示例有效?

find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c "v={}; echo $v"

当我使用它时,$v为空。为什么不将其保存为{}的值?

2 个答案:

答案 0 :(得分:2)

在将字符串传递给$v之前,父shell正在展开xargs

假设您的find命令找到名为./stuff的子目录。

首先,父bash shell(您输入find命令的那个)将展开$v,因为该字符串是双引号。您目前没有为变量v设置值,因此它会扩展为空字符串。

接下来,参数传递给xargs,这将看到:v={}; echo

然后,xargs将从管道中读取./stuff,并将{}替换为./stuff

最后,sh命令由xargs执行,sh会看到:v=./stuff; echo

要解决此问题,您需要转义$以使父shell不扩展它,或使用单引号来避免变量扩展。您还应该引用字符串,以便其中包含空格的任何目录名称不会导致最终sh命令出现问题:

find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c "v=\"{}\"; echo \"\$v\""

OR

find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c 'v="{}"; echo "$v"'

使用任一命令,最终sh进程都会看到:v="./stuff"; echo "$v"

顺便说一句,一种方法可以自己确定这确实发生了什么,就是在父shell中为v设置一个值,然后运行原始命令。 shell会将$v扩展为您设置的任何值,您将看到find找到的每个目录重复该值。

$ v=foobar
$ find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c "v={}; echo $v"
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
...

答案 1 :(得分:0)

使用GNU Parallel,您可以:

find . -mindepth 1 -type d | parallel -P 20 'v={}; echo "$v"'