I have this bash script:gunzip -c /var/log/cisco/cisco.log-$(date +%Y%m%d).gz | awk '/ath_bstuck_tasklet/ { print $4 }' | sort | uniq -c > /tmp/netgear_beacon.txtecho There are  `wc -l /tmp/netgear_beacon.txt | awk '{print $1}'` Stuck beacon; resetting >> /tmp/netgear_beacon.txtgunzip -c /var/log/cisco/cisco.log-`date +%Y%m%d`.gz | awk '/Virtual device ath0 asks to queue packet/ { print $4 }' | sort | uniq -c > /tmp/netgear_buffer_queue.txtecho There are  `wc -l /tmp/netgear_buffer_queue.txt | awk '{print $1}'`  routers with 'Virtual device ath0 asks to queue packet' errors >> /tmp/netgear_buffer_queue.txtgunzip -c /var/log/cisco/cisco.log-`date +%Y%m%d`.gz | awk '/CMS_MSG_DNSPROXY_RELOAD/ { print $4 }' | sort | uniq -c > /tmp/netgear_dns.txtecho There are  `wc -l /tmp/netgear_dns.txt | awk '{print $1}'`  routers with 'DNS Proxy Issue' errors >> /tmp/netgear_dns.txtgunzip -c /var/log/cisco/cisco.log-$(date +%Y%m%d).gz | awk '/beacon/ { print $4 }' | sort | uniq -c > /tmp/netgear_beacon_frame.txtecho There are  `wc -l /tmp/netgear_beacon_frame.txt | awk '{print $1}'` routers with beacon frame errors >> /tmp/netgear_beacon_frame.txtgunzip -c /var/log/cisco/cisco.log-$(date +%Y%m%d).gz | awk '/ACK/ { print $4 }' | sort | uniq -c | awk -v x=50 '$1 >= x' > /tmp/netgear_ACK.txtecho There are  `wc -l /tmp/netgear_ACK.txt | awk '{print $1}'` routers with more than 50 ACK >> /tmp/netgear_ACK.txtI would try to not repeat the gunzip command every time. I would run it just once and use it for all steps. I was thinking a variable, but is it the best practice?
How avoid to repeat the same command in bash script
bash;text processing;awk
There are no best practices. Only things that make sense and make things easier.Extracting the common parts and parameterizing the rest is one such thing:lines=`gunzip -c /var/log/cisco/cisco.log-$(date +%Y%m%d).gz`#gunzip would always output the same thing on the same day, so #just run it once and store the results in a variablegrepAndLog(){  local regex=$1 file=$2 msg=$3 filter=${4:-cat}  #^names for positional parameters  printf %s\n $lines | grep $regex | cut -d' ' -f4 | sort | uniq -c | eval $filter  > /tmp/$file  local count=`wc -l < /tmp/$file`     echo There are $count  $msg >> /tmp/$file}grepAndLog ath_bstuck_tasklet netgear_bacon.txt \ 'Stuck beacon; resetting'grepAndLog netgear_buffer_queue netgear_buffer_queue.txt \ routers with 'Virtual device ath0 asks to queue packet' errorsgrepAndLog CMS_MSG_DNSPROXY_RELOAD netgear_dns.txt \  routers with 'DNS Proxy Issue' errorsgrepAndLog ath_bstuck_tasklet netgear_bacon.txt \  routers with beacon frame errorsgrepAndLog ACK netgear_ACK.txt \  routers with more than 50 ACK 'awk -v x=50 \$1 >= x'It's still a mainly-shell solution. But IMO more readable and over 40% shorter.About the code:I'm using grep $regex | cut -d' ' -f4 instead of the awk expression.Other than that the grepAndLog function is a generalization of what you do in each line of your script:You have some input (the output of gunzip), you grep that for an expression (the $regex parameter), and output the resulting lines, sorted and prefixed with count into a $file. Then you append the line count(I do wc -l < $file instead of wc -l $file | awk ...) wrapped in a message whose beginning is constant and whose end varies ($msg).In your last line you don't simply grep, but you use another filter on top of that.Instead of creating an if branch for that in the function, I simply use cat as an implicit default additional filter in the normal cases where no fourth parameter exists (local filter=${4:-cat} means create a function-local variable filter whose contents is the fourth parameter given to the function, or cat if no fourth parameter is provided). cat gets overriden if a fourth parameter is given to grepAndLog.