from some time I really enjoy bash functions. Let's consider the one that computes average from the n-th column of a file:
avg () { awk -v c="$2" '{n+=$c;m++} END{print n/m,m}' < "$1"; }
Is is possible to rewrite it in such a way that it reads data from pipe? I.e. to use the function in the following:
cat data.txt | avg
A pipe in Bash takes the standard output of one process and passes it as standard input into another process. Bash scripts support positional arguments that can be passed in at the command line. Guiding principle #1: Commands executed in Bash receive their standard input from the process that starts them.
In bash, a pipe is the | character with or without the & character. With the power of both characters combined we have the control operators for pipelines, | and |&. As you could imagine, stringing commands together in bash using file I/O is no pipe dream. It is quite easy if you know your pipes.
Pipe may be the most useful tool in your shell scripting toolbox. It is one of the most used, but also, one of the most misunderstood. As a result, it is often overused or misused. This should help you use a pipe correctly and hopefully make your shell scripts much faster and more efficient.
|| means execute the statement which follows only if the preceding statement failed (returned a non-zero exit code).
avg () { awk -v c="$1" '{n+=$c;m++} END{print n/m,m}'; }
(echo 1 3; echo 2 4; echo 4 6) | avg 2
avg 2 < /tmp/file
If you want to keep the API:
avg () { (if [ "x$1" = "x-" ]; then cat; else cat $1; fi) | awk -v c="$2" '{n+=$c;m++} END{print n/m,m}'; }
(echo 1 3; echo 2 4; echo 4 6) | avg - 2
avg /tmp/file 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With