Shell – Detect if stdin is being piped to in shell function

shell

I have a number of shell functions that I use in my command line environment and in my shell scripts. I want two of them, upper and lower, to behave differently depending on whether or not data is being piped to them. Both functions are currently written such that they receive input through arguments passed to them.

This is the definition of upper:

upper () {
    my_echo "${1}" | tr "[:lower:]" "[:upper:]"
    return 0
}

This is the definition of lower:

lower () {
    my_echo "${1}" | tr "[:upper:]" "[:lower:]"
    return 0
}

(my_echo is a Python script I wrote as a replacement for echo. It's supposed to output whatever gets passed to it as an argument while converting escape sequences into their literals. I'd be able to print any string without it being interpreted as an option, like -e for echo. The way Unix consoles work threw a wrench into that goal, so I shelved it, so you can just ignore it.)

There are several past incarnations of these functions. These are the definitions of the versions that operate on standard input:

upper () {
    tr "[:lower:]" "[:upper:]"
}

lower () {
    tr "[:upper:]" "[:lower:]"
}

If the function being piped to, then it should be operate like the above. If it it isn't, it should read the first parameter.

Best Answer

Your code:

upper () {
    my_echo "${1}" | tr "[:lower:]" "[:upper:]"
    return 0
}

To make this read from standard input if there is no arguments:

upper () {
    ( (( $# )) && printf '%s\n' "$@" || cat ) |
    tr '[:lower:]' '[:upper:]'
}

This tests against $#, the number of positional parameters, and if that's zero it uses cat reading from the standard input stream, otherwise it uses printf on the positional arguments. This is then piped to tr.

I removed return 0 since you're likely to want to know the real exit status of the pipeline.

In bash, you may do

upper () {
    (( $# )) && printf '%s\n' "${@^^}" || tr '[:lower:]' '[:upper:]'
}

When there are arguments, this will not use tr at all but Bash's ${parameter^^pattern} substitution to turn all arguments into uppercase (use ,, to lowercase).

You may or may not want to change the printf format string so that it's '%s ' rather than '%s\n' depending on what you want to achieve.

Related Question