将从 xargs 传递到 bash 的参数保存为变量以进行处理

Saving arguments passed from xargs to bash as a variable for processing

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

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

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

父 shell 扩展 $v 字符串传递给 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\""

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
...

使用 GNU Parallel 你会做:

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