In a splendid lecture, Gary Bernhardt speaks about Bash as being half-assed and at the same time being the right half of the ass. His point, a thought also present in Mendel Coopers Advanced Bash-Scripting Guide, is that Bash is not meant for advanced programming - it is meant for scripting things on the fly, and sometimes saving those scripts. To me, this seems very reasonable.
If we solve a problem with a one-liner in Bash (the interpreter opposed to the scripting language) our solutions will not be pretty. Although most solutions may appear ugly, some are beautiful.
Let's solve a fake-problem using a Bash script, Python, Node.js and Perl 5.
❯ ls_output=$(ls | wc -l) ; if [[ $ls_output -gt 100 ]]; then echo "many files"; else echo "few files"; fi
❯ ls_output=$(ls | wc -l); python -c "print('many files' if $ls_output > 100 else 'few files')"
❯ ls_output=$(ls | wc -l); node -e "console.log($ls_output > 100 ? 'many files' : 'few files')"
I asked a friend how to solve the same task using Perl; I don't know Perl 5, but all of a sudden I am eager to learn it. Be amazed by the beauty of this expression after reading the solutions above:
❯ perl -E'say `ls | wc -l` > 100 ? "many files" : "few files"'
In my eyes, the Perl solution is the only one not looking unattractive. When we see the solutions it is not hard to realize why Perl for a long had a privileged position in Unix environments.
Ask, how many lines of code would you need in node.js, Python or Perl solve the same task not making use of Bash and the command-line interpreter?
The solutions may be ugly, but they work. We don't think, we just do. But if we would use programming languages in a more serious setup, we would have to think, we would have to make use of system API:s, count lines and based on this print one of two messages.
Perhaps you have just re-watched Coppola's Apocalypse Now Redux, and have the first part of The Hollow Men by TS Eliot in a file named hollow.txt. You want to do a word count and number all non-empty lines.
How would we do this with for instance node.js? We would have to involve the fs module, make use of some regular expression but also inject numbers and print this to standard output (or save it to a file).
Or we would go low-tech and use Unix hacker tools and solve it with a one-liner:
❯ cat hollow.txt | wc -w; nl hollow.txt 86 1 We are the hollow men 2 We are the stuffed men 3 Leaning together 4 Headpiece filled with straw. Alas! 5 Our dried voices, when 6 We whisper together 7 Are quiet and meaningless 8 As wind in dry grass 9 or rats' feet over broken glass 10 In our dry cellar 11 Shape without form, shade without colour, 12 Paralysed force, gesture without motion; 13 Those who have crossed 14 With direct eyes, to death's other kingdom 15 Remember us - if at all - not as lost 16 Violent souls, but only 17 As the hollow men 18 The stuffed men.
If we would want to save a version of hollow.txt with line-numbers we would simply do
nl hollow.txt > hollow-numbered.txt.
A solution using node.js or Python could easily be messy, although it's a fairly straight-forward task. But things could go wrong, we would have to think and we would definitly have to write a lot more code.
This is why we should learn hacker tools.