That second example is write-only code, and becomes moreso the more things you have to do with the filename. What if you have to reassemble a few of these into an array, filter that array by matching tokens within it, and then feed those arguments through as NUL-separated stdin to another binary, with error checking all along the way to make sure you never call the final command with invalid arguments?

In bash, that's a 50-line monstrosity. In Ruby (or Python, or even Perl), it's ~5 clean, readable lines.

> I'm pretty sure that's just Bash, if you remember to wrap everything in double-quotes.

Now try composing a command-line in Bash out of those "simply double-quoted values" to pass to ssh as a command to start an ssh exec channel with, where the command also contains a `su -c` stanza.

Again, in another language, that's just a repeated application of a shellescape function as you're composing things. In bash... I have no idea.

---

These are both examples of the type of code you have to write all the time in Bash when dealing with file manipulation, because any file could have any byte-sequence (except NUL) in its name, and you're dealing with the results of calling commands that want to pipe those filenames out to you as raw delimited data (hopefully NUL-delimited.)

Let's say you're writing a script that copies a bunch of files into a dir, and then archives them into a tar file. Are you sure your command reads and recreates both relative and absolute symlinks correctly, in a way that they'll unpack correctly for the tar file? In most scripting languages, you've got functions like Pathname#relative_path_from(dir) and Pathname#clean_path. To get the "correct" symlink in bash, you've got `readlink -f` and a comparison and then a bunch of string manipulations using `basename` and `dirname`.

Or how about a "recursively collapse empty or pseudo-empty directory" function? Where, by "pseudo-empty", I mean "empty except for .DS_Store; Thumbs.db; Desktop.ini; those resource-fork files on FAT volumes/SMB shares that start with ._; or other empty or pseudo-empty directories". That's not a function anything ships with, but it's ~10 lines of Ruby. Try to implement it in Bash! (Yes, you can decide whether to collapse the whole hierarchy in one pass with `find`. But the mission here is to remove all the empty and pseudo-empty dirs found in the hierarchy, like an enhanced version of `find -empty`.)

(Notice that these are both examples of things where a Bash programmer would be likely to say "why not write a new binary in C that does this thing, and then call it from your script"? Well, because the whole reason I'm stuck writing in a scripting language is that this code needs to be portable to unknown target CPU ISAs and OS ABIs, silly.)

There is a reason that the default kind of cloud-init script is a YAML file, rather than a Bash script. There is a reason that Vagrantfiles aren't Bash; a reason that Ansible is less popular than Chef or Puppet or Fabric; a reason why every /bin/init that isn't sysvinit has soundly beaten sysvinit. And it's why, even in Ansible, or autotools, or any package manager's pre-install and post-install hooks, the parts where you do file manipulation are abstracted out, either being done through YAML (Ansible), or through domain-specific file-manipulation binaries (dpkg) or through pre-written and thoroughly-checked file-manipulation Bash scripts (autotools).

And that reason is that doing file manipulation directly in Bash is not worth the time and effort, and especially not worth the maintenance burden in a codebase shared with other programmers who are probably not Bash experts.