Home > Software design >  Stop reading from STDOUT if stream is empty in BASH
Stop reading from STDOUT if stream is empty in BASH

Time:06-26

I am creating a script (myscript.sh) in BASH that reads from STDOUT, typically a stream of data that comes from cat, or from a file and outputs the stream of data (amazing!), like this:

$cat myfile.txt

hello world!

$cat myfile.txt | myscript.sh

hello world!

$myscript.sh myfile.txt

hello world!

But I also would like the following behaviour: if I call the script without arguments I'd like it to output a brief help:

$myscript.sh

I am the help: I just print what you say.

== THE PROBLEM ==

The problem is that I am capturing the stream of data like this:

if [[ $# -eq 0 ]]; then
    stream=$(cat <&0)
   
elif [[ -n "$stream" ]]; then
 
    echo "I am the help:  I just print what you say."
else
    echo "Unknown error."
fi

And when I call the script with no arguments like this: $myscript.sh

It SHOULD print the "help" part, but it just keep waiting for a stream of data in line 2 of code above... Is there any way to tell bash that if nothing comes from STDOUT just break and continue executing?

Thanks in advance.

CodePudding user response:

There's always a standard input stream; if no arguments are given and input isn't redirected, standard input is the terminal.

If you want to treat that specially, use test -t to test if standard input is connected to a terminal.

if [[ $# -eq 0 && -t 0 ]]; then
    echo "I am the help:  I just print what you say."
else
    stream=$(cat -- "$@")
fi

There's no need to test $#. Just pass your arguments to cat; if it gets filenames it will read from them, otherwise it will read from standard input.

CodePudding user response:

First answer is to help your self - try running the script with bash -x myscript.sh. It will include lot of information to help you.

If you specific case, the condition $# -eq 0 was flipped. As per requirement, you want to print the help message is NOT ARGUMENT ARE PROVIDED:

if [[ $# -eq 0 ]] ; then
    echo "I am the help:  I just print what you say."
    exit 0
fi
# Rest of you script, read data from file, etc.
cat -- "$@"

Assuming this approach is taken, and if you want to process standard input or a file, simple pass '-' as parameter: cat foobar.txt | myscript.sh -

CodePudding user response:

I agree to @Barmar's solution.

However, it might be better to entirely avoid a situation where your program behavior depends on whether the input file descriptor is a terminal (there are situations where a terminal is mimicked even though there's none -- in such a situation, your script would just produce the help string).

You could instead introduce a special - argument to explicitly request reading from stdin. This will result in simpler option handling and uniform behavior of your script, no matter what's the environment.

  • Related