Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在bash脚本中将参数回显到xargs中_Bash - Fatal编程技术网

在bash脚本中将参数回显到xargs中

在bash脚本中将参数回显到xargs中,bash,Bash,我想将一些目录传递给bash脚本,然后将这些目录传递给xargs,以便并行工作。不幸的是,我很难让脚本实现我想要的 下面是一个与我的脚本相当的脚本,我尝试使用引号和不使用引号: echo $@ | xargs -i --max-procs=12 echo "do work in {}" echo "$@" | xargs -i --max-procs=12 echo "do work in {}" 输出: $ ./script.sh d* do work in d1 d2 d3 d4 d5 d

我想将一些目录传递给bash脚本,然后将这些目录传递给
xargs
,以便并行工作。不幸的是,我很难让脚本实现我想要的

下面是一个与我的脚本相当的脚本,我尝试使用引号和不使用引号:

echo $@ | xargs -i --max-procs=12 echo "do work in {}"
echo "$@" | xargs -i --max-procs=12 echo "do work in {}"
输出:

$ ./script.sh d*
do work in d1 d2 d3 d4 d5 d6 d7 d8 d9
do work in d1 d2 d3 d4 d5 d6 d7 d8 d9
$ ./script.sh "d*"
do work in d1 d2 d3 d4 d5 d6 d7 d8 d9
do work in d*
你可能已经猜到了,我想要的是:

$ ./script.sh d*
do work in d1
do work in d2
do work in d3
do work in d4
do work in d5
do work in d6
do work in d7
do work in d8
do work in d9
在这个特定的例子中,在脚本中使用
find
是可行的,但将来我可能不想使用目录。例如,如果我传递一个要创建的文件列表,
find
将没有任何用处


如何让xargs将每个参数作为一个单独的项目来接受?

测试版本如下,只是为了进一步强调Jack Yates的原始问题:

printf "%s\0" "$@" | xargs -0 -I xxx --max-procs=4 printf "do work in %s\n" 'xxx'
printf不是处理位置参数的标准方法(对吗?)[ed:Charles:
printf
是POSIX强制要求的功能,因此严格意义上符合标准,但是
xargs
-0
参数不是;但是,截至2004年POSIX标准修订版,没有给出安全地使用任意输入的xargs的纯标准兼容机制。Expanding
“$@”
到printf命令的参数列表中,每个参数重复格式字符串也是符合标准的;请参阅[1]的扩展说明部分中的第9部分

据我所知,与while循环和移位所需的进程数量相比,它非常有效。根据,内置的
printf
命令是
echo
的首选替代品

这是在以下条件下测试的:

  • 超过10000个目录
  • man ascii中找到的所有特殊和不可打印字符都已用于目录名中
  • printf、xargs和bash的手册页和测试证实了Charles Duffy的评论

事先答复(供参考) 以下版本仅供参考。如Charles Duffy所写,当目录名中有特殊字符时,会生成错误

-L 1
选项指示
xargs
分别处理每一行

while [ $# -gt 0 ] ; do echo "${1}"; shift; done \
  | xargs -L 1 -I xxxx --max-procs=12 echo do work in "xxxx"
测试:

$ testscript.sh  .??* *
do work in .bashrc
do work in Downloads
do work in h2-1.2.139.jar
do work in install
do work in testscript.sh
通常,
shift
用于在命令行之外解析参数


之所以使用
-I xxxx
,是因为根据xargs手册页,
-I
已被弃用。

如果要将任意参数传递给
xargs
,唯一安全的方法——正确处理所有可能的文件名,包括带有文字引号、空格或其他格式的文件名——是对它们进行NUL分隔并使用
xargs-0
。因此:

printf '%s\0' "$@" | xargs -0 sh -c 'for f; do printf "do work in %s\n" "$@"; done'

否则,像
$'hello\nworld'
这样包含文字换行符的参数将被视为xargs中的两个参数,而不是真正的单个参数。

我在这方面遇到困难的原因是
-I
-I
选项更改了
xargs的分隔符e> 是预期的。也就是说,
echo“$@”xargs-n1 do something
确实可以按预期工作(注意:如果您有不寻常的文件名,这种方法会有一些警告;有关更多信息,请参阅其他答案),但是
echo“$@”xargs-I{}-n1 do something{
没有。使用
-I
-I
标志,分隔符成为换行符

例如:

$ cat test.sh 
echo "$@" | xargs -n 1 echo "do work in" 
echo "$@" | xargs -n 1 -I{} echo "do work in {}"
$ ls
./  ../  d1/  d2/  d3/  d4/  d5/  d6/  d7/  d8/  d9/  test.sh*
$ ./test.sh d*
do work in d1
do work in d2
do work in d3
do work in d4
do work in d5
do work in d6
do work in d7
do work in d8
do work in d9
do work in d1 d2 d3 d4 d5 d6 d7 d8 d9
man xargs

   -I replace-str
          Replace occurrences of replace-str in the initial-arguments with names read
          from standard input.  Also, unquoted blanks do not terminate  input  items;
          instead the separator is the newline character.  Implies -x and -L 1.

注:根据123对原始问题的评论,
-i
不推荐使用:

   -i[replace-str]
          This option is a synonym for -Ireplace-str if replace-str is specified, and
          for -I{} otherwise.  This option is deprecated; use -I instead.

您可以执行以下两种操作之一:使用带有xargs
-d'
的分隔符标志指示它使用空格作为分隔符,或者使用printf
printf“%s\n”$@
通过换行符分隔参数。此外,您还应该使用
-I{}
而不是
-i
,因为后者已被弃用。我会使用
printf
echo
除了可移植性问题之外,实际上不会为您提供任何额外的东西。(不太相关,但您应该始终引用
$@
;否则,就没有理由过度使用
$*
)所以,很简单,
xargs
希望所有东西都用换行符而不是空格分隔?我知道这是一种不好的做法,但是为什么像
ls | xargs
这样的东西会起作用呢?@JackYates,……更清楚一点,不过,开箱即用,
xargs
尊重空格作为分隔符;这就是为什么它如此破碎的部分原因,since空格在文件名中完全有效。(它也接受引号用于转义这些空格,但引号在文件名中也有效)。将您的原始文件与
echo“$@”| xargs-n1--max procs=12 echo“do work in”
-n
,告诉它只向每个
echo
实例传递一个参数,这是至关重要的。(请原谅之前的
gxargs
--
--max procs
是一个GNUism,在MacOS作为我的平台上测试时,GNU工具有不同的前缀)。这并不是针对不寻常的目录名的证据——要做到这一点,需要(GNU和BSD)
-0
扩展或(仅GNU)
-d
扩展(在bash表示法中,
-d$'\n'
将安全地处理所有不包含文字换行符的文件名,这比默认情况下引号和空格被视为语法的文件名有所改进)。感谢此bash信息。我将尝试一下,然后修改示例。感谢@CharlesDuffy在