When to use Bash and when to use Perl/Python/Ruby?
TL;DR - use bash only for installing a better language (if it isn't already available), otherwise you're wasting unrecoverable, precious human time. If you can't do it on the command line by hand without mistakes, don't script with bash/shell.
It's 2015, so I'd consider the following:
memory overhead
- Ruby/Python runtime memory overhead compared to bash is tiny (because of shared libraries), while one probably can't maintain a non-trivial bash script anyway (i.e. one with > 100 lines) - so memory usage is not a factor
-
- Ruby/Python startup may be a tiny bit slower, but chances are you're not going to be running lots of full Ruby/Python processes in a tight loop 100 times per second (if you have those kinds of needs, bash/shell is too much overhead anyway and you'll probably need to drop to C/C++)
performance
- almost all typical data crunching will be faster in Ruby/Python - or at least comparable (or, you need C/C++/Haskel/OCaml/whatever anyway)
- the real performance/bottleneck in execution (or even productivity) will almost never ever be "a lack of using bash/shell" (even Ubuntu switching dash for startup shows how bash is actually the problem - and a busybox is probably the only use case, because there is nothing more than 'bash' and 'vi' to write and run code, and there's often no way to add/download or store anything else)
- running other processes to do the job (like sed/awk/grep) is actually a magnitude slower than than calling a method on a live object in memory
productivity
- it's too easy to make mistakes in Bash/shell compared to using "real" methods, parameters, variables and exceptions in Ruby/Python
- Agile is mainstream, while Bash has no support for it (lacking in unit testing capabilities, libraries, OO, modularity, linting, introspection, logging, metaprograming; almost impossible to refactor without breaking something)
- way too many incompatibilities with other shells, minor environment variables can completely break a script (and some important dev-ops tools like Puppet ignore shebang lines and pass on or rewrite important shell variables), while Ruby/Python have well-defined relatively smooth migration paths even for major version changes
- learning a new language takes a fraction of the time alternatively spent debugging shell scripts due to shell-specific issues (notably - variable names, no booleans, no exceptions, etc.)
- even startup scripts are a landmine (especially because they can fail during system startup), and given the recent security flaws with bash, you may be better off using plain C (with good libraries) - yes, C needs compiling, configuration, etc., but even a simple shell script may need a repository, then versioning, then packaging anyway.
- whatever is available with sed/awk/grep is likely already built into Ruby/Python - without it being a dependency, or "differences" between versions of those tools across platforms (so what if it works on your setup)
- job security
- what's the point of securing a job you don't like? (unless you love spending all those hours hard-to-debug but trivial-to-make shell script bugs)
I find there's no reason to use Bash/Shell if you have Ruby/Python installed.
And probably getting Ruby/Python installed doesn't even need a bash script in the first place (with the exception of busybox, some system tools depend on Python/Perl being present anyway).
And every time you write a shell script, you're "practicing" doing exactly that - instead of learning something more powerful/productive.
Why do people use Bash nowadays? Because it's a terrible, hard-to-break habit. A script is rarely "finished forever" after the first few minutes - no matter how strongly people tend to think that way. Along with the "it's the last bug in this script" fallacy.
Conclusion: use bash/shell only when you're absolutely forced to (like ~/.bashrc
, busybox), because it's almost never "the right tool for the job" nowadays.
Given a problem that both can handle, you'll want to use the one you're most comfortable with. Ultimately, there are a lot of small details, and only experience can teach you to see them.
Bash is a general purpose scripting language just like Python, Ruby, Perl, but each has different strengths over the rest. Perl excells at text analysis, Python claims to be the most elegant of the bunch, Bash scripts are excellent at "piping stuff around", if you know what I mean, and Ruby... well, Ruby is a little special in a lot of ways.
However, the differences between them only really matter once you have a healthy amount of scripting experience under your belt. I suggest you pick one language and push it to it's limits before moving to the next. You can do a lot in a shell script, more than most people would admit. Any language is just as hard as you want to make it. After you've written a couple things in it, every language is "easy" to you.
Being familiar with the shell pays off quickly if you live in Linux, so maybe you want to start with that. If you find a task you that is impossible or impractical to solve in a shell script, use something else.
Also, bear in mind that learning shell scripting is very simple. The real power of it lies in other programs, like awk, sed, tr, et al.
I use bash when my primary focus is on file handling. This could include moving, copying, and renaming files, as well as using files as input for other programs or storing other program's output in files. I rarely write bash code that actually examines the contents of a file or generates the output to write to a file; I leave that to the other programs (which I may write in Perl or python) that I launch via bash.
I use Perl and python when my primary focus is on reading data from files, processing that data in some way, and writing output to files. If I find myself using (in Perl) the system
command, back ticks or (in python) the subprocess
module too extensively, I consider writing the script in bash. On the other hand, I sometimes start adding so much functionality to a bash script that eventually it makes more sense to rewrite it in Perl/python rather than deal with bash's limited (by comparison) support for variable scoping, functions, data structures, etc.