Bash 使用带引号的文件名列表作为输入调用shell函数

Bash 使用带引号的文件名列表作为输入调用shell函数,bash,xargs,gnu-parallel,Bash,Xargs,Gnu Parallel,使用Bash 我有一个导出的shell函数,我想将其应用于许多文件 通常我会使用xargs,但是像这样的语法(请参阅)太难看了 xargs-n1-p10-I{}bash-c'echo_var“$@”{} 在那次讨论中,parallel的语法更简单: …|并行-P10 echo_var{} 现在我遇到了以下问题:我要应用我的函数的文件列表是一行中的文件列表,每个文件都引用并用空格分隔: “文件1”“文件2”“文件3” 如何将此空格分隔、引用、列表送入并行中 我可以使用echo复制列表进行测试 e、

使用Bash

我有一个导出的shell函数,我想将其应用于许多文件

通常我会使用xargs,但是像这样的语法(请参阅)太难看了

xargs-n1-p10-I{}bash-c'echo_var“$@”{}

在那次讨论中,
parallel
的语法更简单:

…|并行-P10 echo_var{}

现在我遇到了以下问题:我要应用我的函数的文件列表是一行中的文件列表,每个文件都引用并用空格分隔:
“文件1”“文件2”“文件3”

如何将此空格分隔、引用、列表送入并行

我可以使用
echo
复制列表进行测试

e、 g

echo''file1''file2''file3''parallel-d''my_函数{}

但我不能让它工作

我怎样才能修好它

我怎样才能修好它

您必须选择一个唯一的分隔符

echo 'file 1|file 2|file 3' | xargs -d "|" -n1 bash -c 'my_function "$@"' --
echo 'file 1^file 2^file 3' | parallel -d "^" my_function
最安全的方法是使用零字节作为分隔符:

echo -e 'file 1\x00file 2\x00file 3' | xargs -0 ' -n1 bash -c 'my_function "$@"' --
printf "%s\0" 'file 1' 'file 2' 'file 3' | parallel -0 my_function
最好是将元素存储在bash数组中,并使用零分隔流来处理它们:

files=("file 1" "file 2" "file 3")
printf "%s\0" "${files[@]}" | xargs -0 -n1 bash -c 'my_function "$@"' --
printf "%s\0" "${files[@]}" | parallel -0 my_function
请注意,空数组将在没有任何参数的情况下运行函数。有时最好使用
-r
--no run if empty
选项在输入为空时不运行函数。
--no run if empty
parallel
支持,是
xargs
中的gnu扩展(BSD和OSX上的
xargs
没有
--no run if empty

注意:
xargs
默认情况下解析
'
\
。这就是为什么可以使用以下方法:

echo '"file 1" "file 2" "file 3"' | xargs -n1 bash -c 'my_function "$@"' --
echo "'file 1' 'file 2' 'file 3'" | xargs -n1 bash -c 'my_function "$@"' --
echo 'file\ 1 file\ 2 file\ 3' | xargs -n1 bash -c 'my_function "$@"' --
而且它可能会导致一些奇怪的事情,所以请记住几乎总是将
-d
选项指定给
xargs

$ # note \x replaced by single x
$ echo '\\a\b\c' | xargs
\abc
$ # quotes are parsed and need to match
$ echo 'abc"def' | xargs
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
$ echo "abc'def" | xargs
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option

xargs
是一个到处都可以使用的便携工具,而
parallel
是一个GNU程序,必须单独安装。

问题归结为值可以包含空格,空格是值分隔符。因此我们需要一种可以将输入解析为包含空格的单独值的工具。因为它们是bash引用了一个明显的选择,就是使用bash来取消引用这些值

您有几个选择:

(echo "file 1";
 echo "file  2";
 echo "file \"name\" \$(3)") | parallel my_function

printf "%s\n" "file 1" "file  2" "file \"name\" \$(3)" |
  parallel my_function
如果输入在变量中:

var='"file 1" "file  2" "file \"name\" \$(3)"'
eval 'printf "%s\n" '"$var" |
  parallel my_function
也可以将变量转换为数组:

var='"file 1" "file  2" "file \"name\" \$(3)"'
eval arr=("$var")
parallel my_function ::: "${arr[@]}"
如果输入在数组中:

var='"file 1" "file  2" "file \"name\" \$(3)"'
eval arr=("$var")
parallel my_function ::: "${arr[@]}"

无论您使用什么工具,NUL分隔列表都是存储任意参数或文件名列表的最佳选择,因为NUL字符是文件名或UNIX参数中唯一不能使用的字符(因为它们由C字符串组成)。使用它,不需要转义或引号字符,因此您无需担心代码如何处理名称中包含这些字符的文件。因此,我希望,
parallel
能够支持
-0
,就像
xargs
和其他竞争工具一样。假定它支持,您可以运行
printf“%s\0”文件1“文件2”“文件3”并行-0…<代码> BTW,您可能会看到邮件列表线程开始的背景,为什么有些人可能会认为“简单”。“您在这里所指的行为是非常不受欢迎的——甚至比安全使用xargs所需的语法更不受欢迎。xargs语法当然是一口流利的语言,但是对于它的执行方式,它是诚实和明显的;parallel有很多启发和魔力,当这些启发式方法做得不对时,这可能会导致令人惊讶的结果。我尝试了nul分隔选项,但这打破了
命令替换过程的另一部分:在输入中忽略空字节
如果试图将nul文本捕获到字符串变量中,这只是一个问题。不要这样做——NUL分隔字符串之所以有用(用于存储文件名、参数、环境变量或其他任意C字符串的集合),是因为它们本身不能存储在C字符串中。当您想要存储这样一个列表时,请将它将包含的项存储在数组中,然后使用
printf“%s\0”${array[@]}“
将其展开,以便在需要该列表可供使用时立即重新创建流。我想允许用户在
parallel
之后“构造”命令。因此,我的代码以
cmd=“printf'%s\0'${y[@]}parallel-0”
read-e-i“$cmd”结尾;eval“$REPLY”
但这不起作用-我似乎在每个文件之间打印了一个零来执行一个函数
cmd(){printf“%s\0”“$@”| parallel-0 sometthing;}
read something
cmd“$something1”“$something2”“$something3”
输入是数组,但我希望在选择文件后使用的函数输入
my\u
;在我的问题中,我没有清楚地表达这一点,因此我在这里更清楚地提出了这一点: