5

I want to break the whole pipe if the stdin is empty. I try to combined xargs -r and tee, which means not print and write if stdin is empty, but it failed

...| upstream commands | xargs -r tee output.txt | downstream commands | ...

Any feedback appreciated.

1

2 Answers 2

11

There is no way you can actually terminate a bash pipe conditionally. All commands in a pipeline are started simultaneously. There is however a tool available that would assist you with creating a conditional pipeline. In moreutils you can find the tool ifne which executes a command if and only if the input /dev/stdin is not empty. So you could write something like:

$ command1 | ifne command2 | ifne command3 | ifne command4

Here all commands ifne and command1 are started simultaniously. Only if ifne receives input via /dev/stdin, it will start its respective commandx

Sign up to request clarification or add additional context in comments.

Comments

4

Pipe'll break if command failed. You can add grep in between to achieve this. An example:

$ echo ok | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
ok 1 2 3

Now add grep:

$ echo ok | grep -Ei '^.+$' | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
ok 1 2 3

And test empty echo:

$ echo | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
 1 2 3

$ echo | grep -Ei '^.+$' | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'

Looks like this works but it doesn't, interesting indeed, well then obvy pipes don't fit here, try this approach:

#!/bin/bash
set -x

fun(){
    data=$(echo "$1"); [[ $data ]] && data=$(awk '{print $0,1}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print $0,2}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print $0,3}' <<< "$data") || return 1; echo "$data"
}

fun ok
fun

Testing:

$ ./test 
+ fun ok
++ echo ok
+ data=ok
+ [[ -n ok ]]
++ awk '{print $0,1}'
+ data='ok 1'
+ [[ -n ok 1 ]]
++ awk '{print $0,2}'
+ data='ok 1 2'
+ [[ -n ok 1 2 ]]
++ awk '{print $0,3}'
+ data='ok 1 2 3'
+ echo 'ok 1 2 3'
ok 1 2 3
+ fun
++ echo ''
+ data=
+ [[ -n '' ]]
+ return 1

More readable variant:

#!/bin/bash
set -x

fun(){
        data=$(echo "$1")
    [[ $data ]] && data=$(awk '{print $0,1}' <<< "$data") || return 1
    [[ $data ]] && data=$(awk '{print $0,2}' <<< "$data") || return 1
    [[ $data ]] && data=$(awk '{print $0,3}' <<< "$data") || return 1
        echo     "$data"
}

fun ok
fun

2 Comments

This does not break the pipe, it still executes each command. The idea is not to execute the commands
As @kvantour said, actually I want to break the following commands if the last stdout is empty, so as to avoid to generated a lot of empty file by tee in a loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.