xargs拆分换行符而不是空格

fak*_*ake 16 unix shell 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
Run Code Online (Sandbox Code Playgroud)

这是我所期待的,但是

$ 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
Run Code Online (Sandbox Code Playgroud)

输出不应该是?

arg: ac s
arg: bc s
arg: cc s
DONE
Run Code Online (Sandbox Code Playgroud)

如何使用xargs获得第二个输出?

mkl*_*nt0 16

尝试:

printf %b 'ac s\nbc s\ncc s\n' | xargs -d '\n' bash /tmp/test.sh
Run Code Online (Sandbox Code Playgroud)

你忽略了引用\n传递给-d,这意味着刚刚n而非\n传递给xargs作为分隔符-壳"吃"了\(当壳解析一个不带引号的字符串, \用作转义字符;如果一个普通字符如下\- n中这种情况 - 只使用普通字符).

另请注意@glenn jackman建议$@在脚本内部加双引号(或in "$@"完全省略该部分).

另外:xargs -d是一个GNU扩展,例如,它不适用于FreeBSD/macOS.要使它在那里工作,请参阅@glenn jackman的xargs -0解决方案.


请注意,我正在使用printf而不是echo确保\n字符串中的实例在所有类似Bourne的shell中被解释为换行符:
bashksh[1]中,echo默认为NOT解释\基于转义的转义序列(您必须使用它-e来实现) - 不像在zsh和严格的POSIX兼容的外壳,如dash.
因此,printf是更便携的选择.

[1]根据本说明书,kshecho 内置表现出相同的行为,主机平台的外部echo 效用 ; 虽然这可能因平台而异,但Linux和BSD/macOS实现默认解释\转义序列.


cmc*_*nty 13

在 Mac OSX 上

对于具有已知数量 args 的简单情况,告诉 xargs 向每个命令发送多少个 args。例如

$ echo "1\n2\n3" | xargs -n1 echo "#"
# 1
# 2
# 3
Run Code Online (Sandbox Code Playgroud)

当您的输入参数很复杂并且换行符终止时,更好的方法是:

$ echo "1\n2 3\n4 5 6" | xargs -L1 echo  "#"
# 1
# 2 3
# 4 5 6
Run Code Online (Sandbox Code Playgroud)

这里有一个探测器,你能看到吗?如果我们的输入行包含单引号怎么办:

$ echo "1\n2 3\n4 '5 6" | xargs -L1 echo  "#"
# 1
# 2 3
xargs: unterminated quote
Run Code Online (Sandbox Code Playgroud)

xargs不喜欢单引号,除非你使用-0flag。但是-0-L1不兼容,所以我们有:

$ echo "1\n2 3\n4 '5 6" | tr '\n' '\0' | xargs -0 -I{} echo "#" {}
# 1
# 2 3
# 4 '5 6
Run Code Online (Sandbox Code Playgroud)

如果你brew install findutils能做得更好一点:

$ echo "1\n2 3\n4 '5 6" | gxargs -d\\n -i echo "#" {}
# 1
# 2 3
# 4 '5 6
Run Code Online (Sandbox Code Playgroud)

但是等等,也许 usingxargs只是这个工具的一个坏工具。如果我们改用 shell 内置函数会怎样:

$ echo "1\n2 3\n4 '5 6" | while read -r; do echo "# $REPLY"; done
# 1
# 2 3
# 4 '5 6
Run Code Online (Sandbox Code Playgroud)

有关xargsvswhile结帐的更多想法,请查看此问题


gle*_*man 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
Run Code Online (Sandbox Code Playgroud)

对于前者,你得到的相当于

bash /tmp/test.sh ac s bc s cc s
Run Code Online (Sandbox Code Playgroud)

与使用空分隔符

bash /tmp/test.sh "ac s" "bc s" "cc s"
Run Code Online (Sandbox Code Playgroud)

当数据包含空格时,您需要清楚分隔符与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
Run Code Online (Sandbox Code Playgroud)

请注意,在最后一种情况下,额外的arg echo已添加换行符,因此除非您使用,否则不需要额外的换行符echo -n