具有多个参数的 xargs

我有一个源输入,Input.txt

a.txt
b.txt
c.txt

我想把这些输入输入到一个程序中,如下所示:

my-program --file=a.txt --file=b.txt --file=c.txt

所以我尝试使用 Xargs,但没有运气。

cat input.txt | xargs -i echo "my-program --file"{}

它给

my-program --file=a.txt
my-program --file=b.txt
my-program --file=c.txt

但我想

my-program --file=a.txt --file=b.txt --file=c.txt

知道吗?

108059 次浏览

这是因为 echo打印一个换行

echo my-program `xargs --arg-file input.txt -i echo -n " --file "{}`

您可以使用 sed为每行添加 --file=前缀,然后调用 xargs:

sed -e 's/^/--file=/' input.txt | xargs my-program

Xargs 不是这样工作的,试试:

myprogram $(sed -e 's/^/--file=/' input.txt)

这个怎么样:

echo $'a.txt\nb.txt\nc.txt' | xargs -n 3 sh -c '
echo my-program --file="$1" --file="$2" --file="$3"
' argv0

到目前为止给出的所有解决方案都没有正确处理包含空间的文件名。如果文件名包含’或’,有些甚至会失败。如果您的输入文件是由用户生成的,那么您应该准备好应对令人惊讶的文件名。

GNU 并行 很好地处理了这些文件名,并为您(至少)提供了3种不同的解决方案。如果你的程序只有3个参数,那么下面这个方法可行:

(echo a1.txt; echo b1.txt; echo c1.txt;
echo a2.txt; echo b2.txt; echo c2.txt;) |
parallel -N 3 my-program --file={1} --file={2} --file={3}

或者:

(echo a1.txt; echo b1.txt; echo c1.txt;
echo a2.txt; echo b2.txt; echo c2.txt;) |
parallel -X -N 3 my-program --file={}

但是,如果您的程序在命令行中接受尽可能多的参数:

(echo a1.txt; echo b1.txt; echo c1.txt;
echo d1.txt; echo e1.txt; echo f1.txt;) |
parallel -X my-program --file={}

观看介绍视频了解更多: http://www.youtube.com/watch?v=OpaiGYxkSuQ

我正在为这个问题寻找一个解决方案,并得出了编码 剧本在中间的结论。

要转换下一个示例的标准输出,请使用-n’n’分隔符

例如:

 user@mybox:~$ echo "file1.txt file2.txt" | xargs -n1 ScriptInTheMiddle.sh


inside the ScriptInTheMidle.sh:
!#/bin/bash
var1=`echo $1 | cut -d ' ' -f1 `
var2=`echo $1 | cut -d ' ' -f2 `
myprogram  "--file1="$var1 "--file2="$var2

为了使这个解决方案正常工作,你需要在 file1.txt 和 file2.txt 这两个参数之间留出一个空格,或者不管你选择哪个分隔符,还有一件事,在脚本中确保你检查-f1和-f2,因为它们的意思是“取第一个单词并取第二个单词”,这取决于第一个分隔符的位置(分隔符可以是“’;’”单引号之间的任何你想要的。 您可以随意添加任意多的参数。

使用 xargs、 cut 和一些 bash 脚本解决了问题。

干杯!

如果你想通过我有一些有用的提示 http://hongouru.blogspot.com

下面是一个使用 sed 处理三个参数的解决方案,但是它的局限性在于它对每个参数应用相同的转换:

cat input.txt | sed 's/^/--file=/g' | xargs -n3 my-program

这里有一个适用于两个 arg 的方法,但是允许更多的灵活性:

cat input.txt | xargs -n 2 | xargs -I{} sh -c 'V="{}"; my-program -file=${V% *} -file=${V#* }'

不要听他们所有人的。 :)看看这个例子:

echo argument1 argument2 argument3 | xargs -l bash -c 'echo this is first:$0 second:$1 third:$2'

产出将包括:

this is first:argument1 second:argument2 third:argument3

还没有人提到循环中的回显,所以为了完整起见,我将把它放进去(这将是我的第二种方法,sed 方法是第一种) :

for line in $(< input.txt) ; do echo --file=$line ; done | xargs echo my-program

我偶然发现了一个类似的问题,并找到了一个我认为比目前提出的解决方案更好、更干净的解决方案。

我在结尾处使用的 xargs语法将是(对于您的示例) :

xargs -I X echo --file=X

完整的命令行是:

my-program $(cat input.txt | xargs -I X echo --file=X)

就好像

my-program --file=a.txt --file=b.txt --file=c.txt

(提供 input.txt包含来自您的示例的数据)。


实际上,在我的例子中,我首先需要找到文件,并且需要对它们进行排序,因此我的命令行如下所示:

my-program $(find base/path -name "some*pattern" -print0 | sort -z | xargs -0 -I X echo --files=X)

有一些细节可能不太清楚(对我来说不是这样) :

  • 必须引用 some*pattern,否则 shell 将在传递给 find之前展开它。
  • -print0,然后是 -z,最后是 -0使用空分隔来确保正确处理具有空格或其他有线名称的文件。

不过请注意,我还没有对它进行深入的测试。

实际上,这相对容易:

... | sed 's/^/--prefix=/g' | xargs echo | xargs -I PARAMS your_cmd PARAMS

sed 's/^/--prefix=/g'是可选的,以防需要在每个参数前加一些—— prefix = 。

xargs echo将参数行列表(每行一个参数)转换为一行中的参数列表,而 xargs -I PARAMS your_cmd PARAMS允许您运行一个命令,将参数放置在任何您想要的位置。

因此,cat input.txt | sed 's/^/--file=/g' | xargs echo | xargs -I PARAMS my-program PARAMS可以满足您的需要(假设 input.txt 中的所有行都很简单,并且每行只有一个参数值)。

如果使用两个 xargs 调用,则会更简单: 第一个调用将每一行转换为 --file=...,第二个调用实际执行 xargs->

$ cat input.txt | xargs -I@ echo --file=@ | xargs echo my-program
my-program --file=a.txt --file=b.txt --file=c.txt

如果你不知道前面的文件数量,还有另一种不错的方法可以做到这一点:

my-program $(find . -name '*.txt' -printf "--file=%p ")

年代久远,但这是一个更好的答案:

cat input.txt | gsed "s/\(.*\)/\-\-file=\1/g" | tr '\n' ' ' | xargs my_program

# I like clean one liners Gsed 只是 gnu sed,以确保语法与版本 brew install gsed匹配,或者只是 sed,如果您的 ongnu linux 已经..。

测试一下:

cat input.txt | gsed "s/\(.*\)/\-\-file=\1/g" | tr '\n' ' ' | xargs echo my_program