我有一个源输入,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
有什么想法吗?
不要听他们所有人的。 :)看看这个例子:
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
到目前为止给出的解决方案都没有正确处理包含空格的文件名。如果文件名包含 ' 或 ",有些甚至会失败。如果您的输入文件是由用户生成的,您应该为令人惊讶的文件名做好准备。
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
怎么样:
echo $'a.txt\nb.txt\nc.txt' | xargs -n 3 sh -c '
echo my-program --file="$1" --file="$2" --file="$3"
' argv0
如果使用两个 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
您可以使用
sed
在每行前面加上 --file=
,然后调用 xargs
:
sed -e 's/^/--file=/' input.txt | xargs my-program
这是使用 sed 处理三个参数的解决方案,但其局限性在于它对每个参数应用相同的转换:
cat input.txt | sed 's/^/--file=/g' | xargs -n3 my-program
这是一个适用于两个参数的方法,但允许更大的灵活性:
cat input.txt | xargs -n 2 | xargs -I{} sh -c 'V="{}"; my-program -file=${V% *} -file=${V#* }'
我偶然发现了一个类似的问题,并找到了一个解决方案,我认为该解决方案比迄今为止提出的解决方案更好、更干净。
我结束的
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
使用空分隔来确保正确处理带有空格或其他连线名称的文件。但请注意,我还没有对其进行深入测试。虽然它似乎有效。
xargs 不是这样工作的。尝试:
myprogram $(sed -e 's/^/--file=/' input.txt)
这是因为
echo
打印换行符。尝试类似的事情
echo my-program `xargs --arg-file input.txt -i echo -n " --file "{}`
我正在寻找针对这个确切问题的解决方案,并得出在中间编写脚本的结论。
要转换下一个示例的标准输出,请使用 -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 '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 中的所有行都很简单并且每行都可以作为单个参数值)。
如果您不知道前面的文件数量,还有另一种很好的方法:
my-program $(find . -name '*.txt' -printf "--file=%p ")
还没有人提到从循环中回显,所以为了完整起见,我将其放入(这将是我的第二种方法,sed 是第一种):
for line in $(< input.txt) ; do echo --file=$line ; done | xargs echo my-program
旧但这是一个更好的答案:
cat input.txt | gsed "s/\(.*\)/\-\-file=\1/g" | tr '\n' ' ' | xargs my_program
#我喜欢干净的内衬 gsed 只是 gnu sed,以确保语法与版本匹配
brew install gsed
或者只是 sed 如果您已经在 gnu linux 上...
测试一下:
cat input.txt | gsed "s/\(.*\)/\-\-file=\1/g" | tr '\n' ' ' | xargs echo my_program
我发现了一种更直接的方法。您甚至可以根据自己的喜好自定义位置参数的顺序,如下面的演示所示。
set $(cat input.txt)
my-program --file=$1 --file=$3 --file=$2
这在您知道输入中参数的顺序和大小的情况下效果很好。