xargs在换行符时分割而不是空格

时间:2014-04-17 20:25:19

标签: shell unix xargs

这是我的问题,简而言之

$ 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获得第二个输出?

3 个答案:

答案 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)

在Mac OSX上

对于具有已知数量的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

有关xargswhile的更多思考,请查看此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

,否则您不需要额外的换行符