Shell xargs在换行符而不是空格处拆分
简而言之,这就是我的问题Shell xargs在换行符而不是空格处拆分,shell,unix,xargs,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:
$ 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获得第二个输出?试试:
printf %b 'ac s\nbc s\ncc s\n' | xargs -d '\n' bash /tmp/test.sh
您忽略了引用传递给-d
的\n
,这意味着只是n
而不是\n
被传递给xargs
作为分隔符-shell“吃”了\
(当shell解析不带引号的字符串时,\
用作转义字符;在本例中,如果普通字符跟在\
-n
后面,则仅使用该普通字符)
还请注意@glenn jackman的建议,在脚本中重复引用$@
(或者在“$@”部分中完全省略)
另外:xargs-d
是一个GNU扩展,例如,它在FreeBSD/macOS上不起作用。要使它在那里起作用,请参阅@glenn jackman基于xargs-0
的解决方案
请注意,我使用的是printf
而不是echo
,以确保字符串中的\n
实例在所有类似Bourne的shell中都被解释为换行:
在bash
和ksh
[1]中,echo
默认不解释基于\
的转义序列(必须使用-e
才能实现),这与zsh
和严格兼容POSIX的shell(如dash
因此,printf
是更便携的选择
[1] 根据手册,ksh
的echo
内置与主机平台的外部echo
实用程序表现出相同的行为;虽然这可能因平台而异,但Linux和BSD/macOS实现默认情况下不会解释\
转义序列。您的shell脚本需要使用“$@”
非$@
看
我在我的机器上的xargs手册中看到:
xargs从标准输入中读取项目,
由空格[…]或换行符分隔
(强调矿山)
因此:
对于前者,你可以得到相当于
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
已经添加了一个换行符,因此您不需要额外的换行符,除非您在Mac OSX上使用echo-n
对于参数数量已知的简单情况,告诉xargs每个命令要发送多少个参数
$ 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
不喜欢单引号。但是-0
和-L1
不兼容,因此留给我们的是:
$ echo "1\n2 3\n4 '5 6" | tr '\n' '\0' | xargs -0 -I{} echo "#" {}
# 1
# 2 3
# 4 '5 6
如果您brew安装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
vs的更多想法,请检查此问题。好的建议,尽管真正的问题在于没有引用传递给-d
的\n
。您完全正确:这两个问题都需要解决以解决问题(它们各自独立或组合产生症状)。您的printf
-\0
-xargs-0
解决方案是一个不错的替代方案,因为它更便于携带(例如,在xargs-d
不可用的情况下,它也适用于OSX).note-新行并不总是\n
。对于windows,它是\r\n
@ParamvirSinghKarwal:是的,但请注意问题已标记。以防有人在unix环境中摆弄windows样式的文件。“xargs-0-I{}echo”#“{}
”挑剔:在-I
之后应该有一个空格。只有不可移植的-I
选项后面没有空格。
$ echo "1\n2 3\n4 '5 6" | while read -r; do echo "# $REPLY"; done
# 1
# 2 3
# 4 '5 6