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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36186394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 14:24:23  来源:igfitidea点击:

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

bashxargs

提问by Ian Fiddes

I am trying to run many commands in parallel, and need to do some string manipulation on the input first. How can I make the below example work?

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

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

When I use this, $vis null. Why is it not being saved as the value of {}?

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

采纳答案by Mike Holt

The parent shell is expanding $vbeforethe string gets passed to xargs.

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

Suppose your findcommand finds a subdirectory named ./stuff.

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

First, the parent bashshell (the one you typed the findcommand into) will expand $v, because the string is in double quotes. You currently have no value set for variable v, so it expands to an empty string.

首先,父bashshell(你输入find命令的那个)将 expand $v,因为字符串是双引号。您当前没有为 variable 设置值v,因此它扩展为空字符串。

Next, the arguments get passed to xargs, which will see this: v={}; echo

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

Then, xargswill read ./stufffrom the pipe, and replace {}with ./stuff

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

Finally, the shcommand is executed by xargs, and shwill see this: v=./stuff; echo

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

To fix this, you need to either escape the $so that the parent shell doesn't expand it, or use single quotes to avoid variable expansion. You should also probably quote the strings so that any directory names with spaces in them don't cause problems with the final shcommand:

要解决此问题,您需要转义$以便父 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"'

With either command, the final shprocess will see: v="./stuff"; echo "$v"

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

By the way, one way to see for yourself that this is indeed what is happening would be to set a value for vin the parent shell, then run your original command. The shell will expand $vto whatever value you set, and you will see that value repeated for every directory found by find.

顺便说一句,亲眼看到这确实发生了什么的一种方法是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
...

回答by Ole Tange

With GNU Parallel you would do:

使用 GNU Parallel,您可以:

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