Index | Archives | About

Shell Antipatterns

I've been learning stuff about bash rapidly in the last several years, including better and faster ways of accomplishing common tasks. Here are some of my favorites.

Random n lines of a file

Antipattern

ls | shuf | head -n1

Improvement

ls | shuf -n1

I learned this week that the venerable shuf utility comes with functionality to select the top "n" lines of the file produced by the last pipe step! This saves an invocation of head and a good bit of typing.

Filter by lines with grep, then by column with awk

Antipattern

ls -lt | grep -E '^d' | awk '{print $2}'

Improvement

ls -lt | awk '/^d/{print $2}'

I did this for years until someone sat me down and explained a bit more of awk to me. If there was an award for "useless use of grep", it would go to this common shell pattern I see every day. If you're looking to filter lines by a regular expression, then filter down to a specific column, awk can take care of all of that for you. Everything inside the // is an extended PCRE, so you don't have to pass any flags (like grep) to get what you want.

Unnecessary loops

Antipattern

git ls-files | while read line; do rm "$line"; done

Improvement

git ls-files | xargs -L 1 rm

If you're only executing a single command against each element of a bash loop, you can quickly replace your use of the loop with an xargs invocation. The -L 1 flag for xargs allows you to process each line of input separately- exactly like a bash while loop. If you don't care about the serialization of the operations in this loop, you can parallelize it with xargs -P

© Jamie Luck. Built using Pelican. Theme by Jamie Luck on github.