2

My bash script (lets call it myscript) takes input either from stdin (pipe), or form a regular file (if filename was provided as an argument)

a) someprog | myscript

   or

b) myscript file.txt

Then, the data is processed line by line. At the moment, my code looks something like the following:

if [ -t 0 ] ; then
    while read LINE
      do
         prog_1
         prog_2
         ...
         prog_n
      done
else
    while read LINE
      do
         prog_1
         prog_2
         ...
         prog_n
      done < $1
fi

This script works fine, but there seems to be too much duplicity. I am wondering whether there is a better (more elegant) way to do it. All the steps 1 to n are the same. The only difference is whether there is a < $1 at the end or not. is there no better way to do it?

5

Functions are the general way to reduce code duplication. This case isn't any different. You just need to to define a function to implement your while read logic.

myfunc() {
    while read LINE
    do
        prog_1
        prog_2
        ...
        prog_n
    done
}

if [[ -t 0 ]]; then
    myfunc # read stdin passed to the script
else
    myfunc < "$1" # redirect file to stdin
fi
2

I usually use

cat "$@" | while read line ; do
    ...
done

The only problem might be if someone calls someprog | myscript file.txt (but the same problem exists in the original code).

2

If an argument is given, redirect stdin from it then reuse the code.

if [ -t 0 ]; then
    exec 3<&0
elif (( $# > 0 )) && [[ -r $1 ]]; then
    exec 3<"$1"
else
    echo no stdin and no file to read
    exit 1
fi

while IFS= read -r -u 3 LINE; do
     prog_1
     prog_2
     ...
     prog_n
done

exec 3<&-

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.