这是我的问题,简而言之
$ echo 'for i in $@; do echo arg: $i; done; echo DONE' > /tmp/test.sh
$ echo "ac\nbc\ncc\n" | xargs bash /tmp/test.sh
arg: ac
arg: bc
arg: cc
DONE
这是我所期待的,但
$ echo "ac s\nbc s\ncc s\n" | xargs -d \n bash /tmp/test.sh
arg: ac
arg: s
arg: bc
arg: s
arg: cc
arg: s
DONE
输出不应该是?
arg: ac s
arg: bc s
arg: cc s
DONE
如何使用xargs获得第二个输出?
答案 0 :(得分:16)
尝试:
printf %b 'ac s\nbc s\ncc s\n' | xargs -d '\n' bash /tmp/test.sh
您忽略了引用传递给\n
的{{1}} ,这意味着只有-d
而不是n
传递给{{1}作为分隔符 - shell" ate" \n
(当shell解析一个不带引号的字符串时,xargs
用作转义字符;如果在这种情况下普通字符跟\
- \
之后 - 只有普通字符字符被使用)。
另请注意@glenn jackman建议在脚本中双引\
(或完全忽略n
部分)。
另外: $@
是一个GNU扩展,例如,它不能在FreeBSD / macOS上工作。要使其在那里工作,请参阅@glenn jackman的基于in "$@"
的解决方案。
请注意,我使用xargs -d
而不是xargs -0
来确保字符串中的printf
个实例被解释为 all Bourne中的换行符式壳:
在echo
和\n
[1] 中,bash
默认为NOT解释基于ksh
的转义序列(您必须使用echo
实现这一点) - 与\
和严格的POSIX兼容的shell(例如-e
不同。)
因此,zsh
是更便携的选择。
[1]根据手册,dash
' printf
内置表现出与主机平台外部相同的行为ksh
实用程序;虽然这可能因平台而异,但Linux和BSD / macOS实现默认情况下不解释echo
转义序列。
答案 1 :(得分:9)
对于具有已知数量的arg的简单情况,请告诉xargs发送给每个命令多少个arg。例如
$ echo "1\n2\n3" | xargs -n1 echo "#"
# 1
# 2
# 3
当您的输入参数很复杂并且换行符终止时,更好的方法是:
$ echo "1\n2 3\n4 5 6" | xargs -L1 echo "#"
# 1
# 2 3
# 4 5 6
这里有一个探针,可以看到吗?如果我们的输入行包含单引号怎么办:
$ echo "1\n2 3\n4 '5 6" | xargs -L1 echo "#"
# 1
# 2 3
xargs: unterminated quote
xargs
不喜欢单引号unless you use the -0
flag。但是-0
和-L1
不兼容,因此我们可以:
$ echo "1\n2 3\n4 '5 6" | tr '\n' '\0' | xargs -0 -I{} echo "#" {}
# 1
# 2 3
# 4 '5 6
如果您brew install findutils
,我们可以做得更好:
$ echo "1\n2 3\n4 '5 6" | gxargs -d\\n -i echo "#" {}
# 1
# 2 3
# 4 '5 6
但是,等等,也许使用xargs
只是一个不好的工具。如果我们改用shell内置的东西怎么办:
$ echo "1\n2 3\n4 '5 6" | while read -r; do echo "# $REPLY"; done
# 1
# 2 3
# 4 '5 6
有关xargs
与while
的更多思考,请查看此question。
答案 2 :(得分:5)
您的shell脚本需要使用"$@"
而不是$@
请参阅http://www.gnu.org/software/bash/manual/bashref.html#Special-Parameters
我在我的机器上的xargs手册中看到了:
xargs从标准输入中读取项目, 由空白[...]或换行符
分隔
(强调我的)
因此:
$ echo $'ac s\nbc s\ncc s\n' | xargs bash /tmp/test.sh
arg: ac
arg: s
arg: bc
arg: s
arg: cc
arg: s
DONE
$ printf "%s\0" "ac s" "bc s" "cc s" | xargs -0 bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
DONE
对于前者,你得到相当于
bash /tmp/test.sh ac s bc s cc s
与使用空分隔符
bash /tmp/test.sh "ac s" "bc s" "cc s"
当数据包含空格时,您需要清楚分隔符与xargs的对应关系。
$ printf "%s\n" "ac s" "bc s" "cc s" | xargs -d $'\n' bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
DONE
$ echo $'ac s\nbc s\ncc s\n' | xargs -d $'\n' bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
arg:
DONE
请注意,在最后一种情况下,echo
已经添加了换行符,因此除非您使用echo -n