9

Let's say I have a bash command mycommand. Sometimes it writes something to output but always return exit code 0. I need use pipe to fix the exit code to be 0 for empty output and something else for non-empty output.

mycommand | ???

I'm not interested in ifs nor custom commands. I want just a simple command like grep with some parameters to check if its input is empty and return the exit code.

Preferably it should print the input if it is not empty but it's not mandatory.

2
  • 1
    Why do you "need to use pipe"? Commented Mar 19, 2017 at 11:25
  • Not "need", just "want". Anyway this is the best answer I got from comments: ! (mycommand | grep ^) Commented Mar 19, 2017 at 15:44

5 Answers 5

7

Maybe:

yourcommand | grep -qv .

! ( yourcommand |  grep -q ^ )

Or inverse meaning: return false if nothing returned:

yourcommand |  grep -q ^ || echo no output.
Sign up to request clarification or add additional context in comments.

13 Comments

I know about that but I'd like to avoid the negation. It doesn't matter if its grep or something else.
Without negation, you have to inverse the meaning of condition.
If the empty line counts as output (such from the simple echo) should test the ^ instead of the .. e.g. echo | grep -q ^ || echo no vs echo | grep -q . || echo no
I'll go with ! (mycommand | grep ^) for now (no -q because I want to see the output). Something without the ! would be prefered though.
Then grep -v ^ though again, that will not display anything. Your obsession with avoiding the ! seems irrational.
|
6

wc supports newlines and \0:

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

So this would be a simple POSIX compliant way to do it:

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

Examples:

$ 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

Alternatives which don't work:

  • grep . doesn't match a solitary newline or \0 as a character:

    $ printf '\n' | grep .; echo $?
    1
    $ printf '\0' | grep .; echo $?
    1
    
  • You can't save \0 in a variable:

    $ a=$'foo\0bar\0baz'
    $ printf '%s' "$a" | wc -c
    3
    
  • Command substitutions remove trailing newlines:

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

3 Comments

echo will return an empty line! Try with echo -n or true!
@F.Hauri Fixed. The current solution works for newlines and \0 as well.
@l0b0 using the ^ the grep will work ...
1

Because many different answers - so grep using the ^.

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

output

================
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

3 Comments

pp() { local sline;eval "printf -v sline '%.0s-' {1..$COLUMNS}";printf "%s\nFor: <%s>:\n" $sline "$1";printf "$1" | grep ^ ; echo "Returned code: $?"; }
You could run pp without argument, for sample. Then printf... ${1:-no output}... But you already know that.
read -v COLUMNS < <(tput cols), then with fixed input eval is not evil! There is no issue using eval in this way.
1

Seems that the cleanest way is

mycommand | ( ! grep ^ )

1 Comment

The negation can also be in the very beginning: ! mycommand | grep ^
0

A common, though slightly inelegant, workaround is to use a temporary file.

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

This is obviously too complex to use casually on the command line, but sometimes you just have to write a script.

This generalizes nicely to any situation where you need to perform multiple commands on all of the input.

I will note in passing also xargs -r which of course only makes sense if you're piping to xargs already.

1 Comment

Thanks but no thanks. I want an elegant one-liner into my .travis.yml

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.