【问题标题】:Bash: check if input is empty in pipe [duplicate]Bash:检查管道中的输入是否为空[重复]
【发布时间】:2017-03-19 07:50:38
【问题描述】:

假设我有一个 bash 命令mycommand。有时它会写一些东西输出,但总是返回退出代码 0。我需要使用管道将退出代码修复为空输出为 0,非空输出为其他内容。

mycommand | ???

我对 ifs 和自定义命令不感兴趣。我只想要一个简单的命令,比如带有一些参数的 grep 来检查它的输入是否为空并返回退出代码。

如果输入不为空但不是强制性的,最好打印输入。

【问题讨论】:

  • 为什么“需要使用管道”?
  • 不是“需要”,只是“想要”。无论如何,这是我从 cmets 得到的最佳答案:! (mycommand | grep ^)

标签: bash


【解决方案1】:

wc 支持换行符和\0

$ printf '\n' | wc -c
1
$ printf '\0' | wc -c
1

所以这将是一种简单的 POSIX 兼容方式:

mycommand | [ $(wc -c) -eq 0 ]

例子:

$ printf '' | [ $(wc -c) -eq 0 ]; echo $?
0
$ printf 'yay' | [ $(wc -c) -eq 0 ]; echo $?
1
$ printf '\n' | [ $(wc -c) -eq 0 ]; echo $?
1
$ printf '\0' | [ $(wc -c) -eq 0 ]; echo $?
1

不起作用的替代方法

  • grep . 不匹配单独的换行符或 \0 作为字符:

    $ printf '\n' | grep .; echo $?
    1
    $ printf '\0' | grep .; echo $?
    1
    
  • 您不能将\0 保存在变量中:

    $ a=$'foo\0bar\0baz'
    $ printf '%s' "$a" | wc -c
    3
    
  • Command substitutions 删除尾随换行符:

    $ test -z "$(printf '\n')"; echo $?
    0
    

【讨论】:

  • echo 将返回一个空行!试试echo -ntrue
  • @F.Hauri 已修复。当前的解决方案也适用于换行符和\0
  • @l0b0 使用^grep 将工作...
【解决方案2】:

也许:

yourcommand | grep -qv .

! ( yourcommand |  grep -q ^ )

或反义:如果没有返回则返回false

yourcommand |  grep -q ^ || echo no output.

【讨论】:

  • 我知道这一点,但我想避免否定。不管是 grep 还是别的什么。
  • 没有否定,你必须反转条件的含义。
  • 如果空行算作输出(例如来自简单的echo)应该测试^ 而不是.。例如echo | grep -q ^ || echo noecho | grep -q . || echo no
  • 我现在选择! (mycommand | grep ^)(没有-q,因为我想查看输出)。没有的东西!不过会更喜欢。
  • 然后grep -v ^ 再次,不会显示任何内容。你对避免! 的痴迷似乎是不合理的。
【解决方案3】:

因为许多不同的答案 - 所以grep 使用^

pp() { printf "================\nfor: %s\n" "$@"; }

pp "no input"
printf '' | grep -q ^ ; echo $?
printf '' | grep -q ^ && echo got input || echo no input

pp 'null character'
printf '\0' | grep -q ^ ; echo $?
printf '\0' | grep -q ^ && echo got input || echo no input

pp '\n'
printf '\n' | grep -q ^ ; echo $?
printf '\n' | grep -q ^ && echo got input || echo no input

pp 'some'
printf 'some' | grep -q ^ ; echo $?
printf 'some' | grep -q ^ && echo got input || echo no input

pp 'some\n'
printf 'some\n' | grep -q ^ ; echo $?
printf 'some' | grep -q ^ && echo got input || echo no input

输出

================
for: no input
1
no input
================
for: null character
0
got input
================
for: \n
0
got input
================
for: some
0
got input
================
for: some\n
0
got input

【讨论】:

  • pp() { local sline;eval "printf -v sline '%.0s-' {1..$COLUMNS}";printf "%s\nFor: <%s>:\n" $sline "$1";printf "$1" | grep ^ ; echo "Returned code: $?"; }
  • 您可以在没有参数的情况下运行pp,例如。然后printf... ${1:-no output}...但是你已经知道了。
  • read -v COLUMNS < <(tput cols),那么固定输入eval不是邪恶!以这种方式使用eval 没有问题。
【解决方案4】:

一种常见但略显不雅的解决方法是使用临时文件。

t=$(mktemp -t myscript.XXXXXXXX) || exit
# Use a trap to clean up even if interrupted
trap 'rm -f "$t"' EXIT
trap 'exit' HUP TERM
cat >"$t"
if [ -s "$t" ]; then
    : do stuff with "$t"
fi

这显然太复杂了,不能在命令行上随便使用,但有时你只需要写一个脚本。

这很好地概括了您需要对所有输入执行多个命令的任何情况。

顺便提一下xargs -r,这当然只有在您已经通过管道发送到xargs 时才有意义。

【讨论】:

  • 谢谢,但不,谢谢。我想要一个优雅的单线进入我的 .travis.yml
【解决方案5】:

似乎最干净的方法是

mycommand | ( ! grep ^ )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-18
    • 2015-05-11
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-03-26
    • 2018-05-26
    • 2022-12-16
    相关资源
    最近更新 更多