在OsX下,xargs -r的等价物是什么

时间:2012-01-10 13:27:18

标签: macos bash shell

它们在OSX下是否与Linux下的xargs -r相当?如果没有数据,我正试图找到一种方法来中断管道。

例如,假设您执行以下操作:

touch test
cat test | xargs -r echo "content: "

这不会产生任何结果,因为xargs会中断管道。

是否有一些隐藏 xargs选项或其他东西在OSX下实现相同的结果?

8 个答案:

答案 0 :(得分:2)

您可以使用test[

if [ -s test ] ; then cat test | xargs echo content: ; fi

答案 1 :(得分:2)

xargs的POSIX标准要求命令执行一次,即使没有参数。这是一个令人讨厌的问题,这就是GNU xargs具有-r选项的原因。不幸的是,BSD(MacOS X)和其他主流Unix版本(AIX,HP-UX,Solaris)都不支持它。

如果对您至关重要,请在您的环境找到的地方获取并安装GNU xargs,而不会影响系统(因此,除非您是勇敢的人,否则不要替换/usr/bin/xargs我是 - 但/usr/local/bin/xargs可能没问题,或$HOME/bin/xargs或......)。

答案 2 :(得分:2)

没有标准方法可以确定您运行的xargs是否为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'
cat foo | portable_xargs_r echo "content: "
echo '=== DONE.'

cat </dev/null > foo
echo '=== Expect zero lines'
cat foo | portable_xargs_r echo "content: "
echo '=== DONE.'

答案 3 :(得分:1)

使用POSIX xargs¹,为避免在输入为空时运行the-command,可以使用moreutils的{​​{1}}(对于,如果不为空< / em>):

ifne

或使用... | ifne xargs ... the-command ... 包装器检查参数数量:

sh

¹,尽管几乎不使用... | xargs ... sh -c '[ "$#" -eq 0 ] || exec the-command ... "$@"' sh ,因为它不支持xargs,当输入为非文本时(例如,在大多数系统上不是这样的文件名),具有不确定的行为保证是POSIX语言环境以外的文本),以一种非常神秘的方式解析其输入,并且取决于语言环境,并且如果任何单词的长度超过255个字节,则不做任何保证!

答案 4 :(得分:0)

您可以确保输入始终至少有一行。这可能并不总是可行的,但你会惊讶地发现有多少创造性的方法可以做到。

答案 5 :(得分:0)

这是一个使用临时文件的快速而脏的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"

答案 6 :(得分:0)

一个典型的用例如下:

find . -print0 | xargs -r -0 grep PATTERN

某些版本的xargs没有-r标志。在这种情况下,您可以提供/ dev / null作为第一个文件名,以便grep永远不会收到文件名的空列表。由于永远不会在/ dev / null中找到该模式,因此不会影响输出:

find . -print0 | xargs  -0 grep PATTERN /dev/null

答案 7 :(得分:0)

您可以测试流中是否有任何内容:

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: "

此方法在子壳内部的管道内部运行检查,因此可以有效地用于复杂的管道设置中。