将从 xargs 传递给 bash 的参数保存为用于处理的变量

Ian*_*des 6 bash xargs

我正在尝试并行运行许多命令,并且需要先对输入进行一些字符串操作。我怎样才能让下面的例子工作?

find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c "v={}; echo $v"
Run Code Online (Sandbox Code Playgroud)

当我使用它时,$v为空。为什么它没有被保存为的值{}

Mik*_*olt 6

父外壳扩展$v 之前的字符串被传递给xargs

假设您的find命令找到一个名为./stuff.

首先,父bashshell(你输入find命令的那个)将 expand $v,因为字符串是双引号。您当前没有为 variable 设置值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\""
Run Code Online (Sandbox Code Playgroud)

或者

find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c 'v="{}"; echo "$v"'
Run Code Online (Sandbox Code Playgroud)

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

顺便说一句,亲眼看看这确实发生了什么的一种方法是v在父 shell 中设置一个值,然后运行您的原始命令。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
...
Run Code Online (Sandbox Code Playgroud)