具有多个参数的 xargs
Posted
技术标签:
【中文标题】具有多个参数的 xargs【英文标题】:xargs with multiple arguments 【发布时间】:2011-04-15 18:53:31 【问题描述】:我有一个源输入,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
有什么想法吗?
【问题讨论】:
【参考方案1】:如果您不知道文件的数量,还有另一种很好的方法:
my-program $(find . -name '*.txt' -printf "--file=%p ")
【讨论】:
【参考方案2】:不要听所有人的。 :) 看看这个例子:
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
【讨论】:
哈哈。 “不要听他们所有人的”我笑了。 如果您尝试在 OSX 上执行此操作,请使用 -L1 例如echo argument1 argument2 argument3 | xargs -L1 bash -c 'echo this is first:$0 second:$1 third:$2' | xargs
但我认为这个答案是不正确的。该文件有 3 行,但在这个答案中,1 行中有 3 个参数!
为什么最后第二次需要到 xargs 的管道?
您必须在 makefile 中使用双 $ 符号。示例:echo zero one | xargs -L1 -n 4 sh -c 'echo $$0'
【参考方案3】:
我偶然发现了一个类似的问题,并找到了一个我认为比目前提出的解决方案更好、更简洁的解决方案。
我已经结束的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
,使用空分隔符来确保正确处理带有空格或其他连线名称的文件。
但是请注意,我还没有深入测试它。虽然它似乎有效。
【讨论】:
【参考方案4】:如果你使用两个 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
【讨论】:
【参考方案5】:其实还是比较简单的:
... | 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 中的所有行都很简单,并且每行都可以作为单个参数值)。
【讨论】:
【参考方案6】:还没有人提到从循环中回显,所以为了完整起见,我会把它放进去(这将是我的第二种方法,sed 是第一种):
for line in $(< input.txt) ; do echo --file=$line ; done | xargs echo my-program
【讨论】:
【参考方案7】:这是一个将 sed 用于三个参数的解决方案,但其局限性在于它对每个参数应用相同的转换:
cat input.txt | sed 's/^/--file=/g' | xargs -n3 my-program
这是一种适用于两个 args 的方法,但具有更大的灵活性:
cat input.txt | xargs -n 2 | xargs -I sh -c 'V=""; my-program -file=$V% * -file=$V#* '
【讨论】:
【参考方案8】:我一直在为这个确切的问题寻找解决方案,并得出了编写中间脚本的结论。
要为下一个示例转换标准输出,请使用 -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
【讨论】:
【参考方案9】:到目前为止,没有一个解决方案能正确处理包含空格的文件名。如果文件名包含 ' 或 ",有些甚至会失败。如果您的输入文件是由用户生成的,您应该为令人惊讶的文件名做好准备。
GNU Parallel 可以很好地处理这些文件名,并(至少)为您提供 3 种不同的解决方案。如果您的程序需要 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
【讨论】:
有趣 - 不了解 GNU Parallel。 Bash 是一个健全的外壳;你不需要在管道后面加上反斜杠来告诉它命令的其余部分在下一行。 GNU 并行非常棒。警告一句:在某些系统上,您需要并行提供“--gnu”选项以使其合理工作。我再也不用 xargs 了。如果您真的不想并行化,您可以随时给它“-j 1”选项(1 个作业)。 Utiliteparallel
并不总是可用的,尤其是在普通的 unix 中,如果可能的话需要安装。有有趣的解决方案 below 可用于标准 unix 工具。
Another, more flexible solution with standard tools【参考方案10】:
怎么样:
echo $'a.txt\nb.txt\nc.txt' | xargs -n 3 sh -c '
echo my-program --file="$1" --file="$2" --file="$3"
' argv0
【讨论】:
【参考方案11】:xargs 不能那样工作。试试:
我的程序 $(sed -e 's/^/--file=/' input.txt)【讨论】:
【参考方案12】:您可以使用sed
在每一行添加--file=
前缀,然后调用xargs
:
sed -e 's/^/--file=/' input.txt | xargs my-program
【讨论】:
在谷歌之后(四年后),我想出了自己的(类似的)解决方案......具体来说,对于这个问题,它更像是:echo a.txt b.txt c.txt | xargs | sed 's/ / --file=/g' | xargs echo my-program --file
我的复杂解决方案更多的是通过管道将文件名(例如 Apache 日志)输入到长命令行中。例如:ls /var/log/apache2/*access.log | xargs | sed 's/ / -f /g' | xargs echo myprogram -f
【参考方案13】:
这是因为echo
打印了一个换行符。尝试类似
echo my-program `xargs --arg-file input.txt -i echo -n " --file "`
【讨论】:
当输入达到 30,000 个文件名时会发生什么? 使用子shell扩展,如echo my-program $(xargs --arg-file input.txt -i echo -n " --file ")
以上是关于具有多个参数的 xargs的主要内容,如果未能解决你的问题,请参考以下文章
Linux xargs 命令(给命令传递参数的一个过滤器,也是组合多个命令的一个工具)(通常与管道配合使用)