在OSX下有没有与Linux下的xargs -r
相当的类似命令?我正在尝试找到一种在没有数据的情况下中断管道的方法。
例如,假设你执行以下操作:
touch test
cat test | xargs -r echo "content: "
那样做没有结果,因为xargs会打断管道。
在OSX下是否有一些隐藏的xargs选项或其他方式可以达到相同的效果?
xargs
的规定是,即使没有参数,该命令也必须执行一次。这很麻烦,这就是为什么GNU xargs
有-r
选项的原因。不幸的是,BSD(MacOS X)和其他主流Unix版本(AIX、HP-UX、Solaris)都不支持它。xargs
,而不影响系统(因此不要替换/usr/bin/xargs
,除非你比我更勇敢——但/usr/local/bin/xargs
可能没问题,或者$HOME/bin/xargs
,或者……)。test
或[
:if [ -s test ] ; then cat test | xargs echo content: ; fi
判断正在运行的xargs是否为GNU或非GNU没有标准方法。我将$gnuargs
设置为"true"或"false",然后编写一个函数来替换xargs并执行正确的操作。
在Linux、FreeBSD和MacOS上,这个脚本对我来说很有效。xargs的POSIX标准规定即使没有参数也必须执行命令一次。FreeBSD和MacOS X违反了这个规则,因此不需要"-r"选项。GNU发现这很烦人,添加了-r
选项。这个脚本可以执行正确的操作,如果你找到另一种Unix版本,请进行改进。
#!/bin/bash
gnuxargs=$(xargs --version 2>&1 |grep -s GNU >/dev/null && echo true || echo false)
function portable_xargs_r() {
if $gnuxargs ; then
cat - | xargs -r "$@"
else
cat - | xargs "$@"
fi
}
echo 'this' > foo
echo '=== Expect one line'
portable_xargs_r <foo echo "content: "
echo '=== DONE.'
cat </dev/null > foo
echo '=== Expect zero lines'
portable_xargs_r <foo echo "content: "
echo '=== DONE.'
xargs
即使没有-r
选项的支持,也能够正常运行,但是在我的Mac上,xargs ls < /dev/null
没有任何输出;它的行为就像已经指定了-r
选项一样。 - Jonathan Lefflercat
? - Stephane Chazelas"$@"
和"""$@"""
之间唯一的区别在于,如果向portable_xargs_r
传递了零个参数,则后者会导致xargs
被传递一个空参数,从而防止其运行默认的echo
命令。 - Stephane Chazelascat
s:cat foo
已被删除。它们只是为了保持并行性。cat -
在可移植的方式中表示“cat标准输入”,其他shell可能也有适用的简写形式。 - TomOnTime这是一个快速而简单的 xargs-r
,使用临时文件。
#!/bin/sh
t=$(mktemp -t xargsrXXXXXXXXX) || exit
trap 'rm -f $t' EXIT HUP INT TERM
cat >"$t"
test -s "$t" || exit
exec xargs "$@" <"$t"
使用 POSIX xargs
¹,为了避免在输入为空时运行 the-command
,您可以使用 moreutils
的 ifne
(表示如果不为空):
... | ifne xargs ... the-command ...
或者使用一个检查参数数量的sh
包装器:
... | xargs ... sh -c '[ "$#" -eq 0 ] || exec the-command ... "$@"' sh
¹虽然人们几乎不能在POSIX上使用xargs
,因为它不支持-0
,当输入是非文本时(例如文件名,在大多数系统上除了POSIX语言环境外不能保证是文本),以非常晦涩的方式解析其输入,并且这是与语言环境相关的,而且如果任何单词超过255个字节长度,它不会给出任何保证!
一个典型的使用案例如下:
find . -print0 | xargs -r -0 grep PATTERN
某些版本的xargs没有-r
标志。在这种情况下,您可以将/dev/null作为第一个文件名提供,以便grep永远不会被交付一个空的文件名列表。由于该模式永远不会在/dev/null中找到,因此这不会影响输出:
find . -print0 | xargs -0 grep PATTERN /dev/null
-r
的作用是在没有输入行的情况下 阻止 执行命令。 - Thomas您可以测试流是否有任何内容:
cat test | { if IFS= read -r tmp; then { printf "%s\n" "$tmp"; cat; } | xargs echo "content: "; fi; }
# ^^^ - otherwise just do nothing
# ^^^^^^^^^^^^^^^^^^^^^^^ - to xargs
# ^^^ - and the rest of input
# ^^^^^^^^^^^^^^^^^^^^^^ - redirect first line
# ^^^^^^^^^^^^^^^^^^^ - try reading anything
# or with a function
# even TODO: add the check of `portable_xargs_r` in the other answer and call `xargs -r` when available.
xargs_r() {
if IFS= read -r tmp; then
{ printf "%s\n" "$tmp"; cat; } | xargs "$@"
fi
}
cat test | xargs_r echo "content: "