Much credit to copilot and shellcheck, which have made complex bash ever the more write-only language than it already was.
Much credit to copilot and shellcheck, which have made complex bash ever the more write-only language than it already was.
Every time I have to express logic in YAML, I miss shell. Shell’s really not great, and it could be improved upon (my vote? Tcl), but it’s so much better than where the industry is these days.
I think in part it's a skills mismatch - a lot of devops/sysadmin type folks I encounter, while very talented, are not prolific coders. So code-forward solutions like jsonnet, starlark, dhall, nix, etc. are rather unfamiliar familiar.
It doesn't help that all but one of those languages mentioned are odd little functional languages, increasing the familiarity gap even further.
My bugbear is that "alias p=printf" works well in any POSIX shell script, including bash when it is invoked as #!/bin/sh - but when called as #!/bin/bash, the alias (used in a script) fails with an error.
While the Korn shell managed to evolve and comply with the POSIX standard, bash decided to split the personality, so one solution to the above alias failure is to toggle POSIX mode.
Bash was forced to do this, to keep a decade of shell scrips that were written for it working. Pity.
The standard for the POSIX shell looked very hard at Korn, and credits it. Bash is not mentioned.
$ cat l.sh
alias l=ls
l
$ sh l.sh
file1 file2 l.sh
$ bash l.sh
l.sh: line 2: l: command not found
$ bash -i l.sh
file1 file2 l.sh
Edit: Ah yes, the man page says so.> Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt
BTW aliases come from csh, and there they support arguments, which makes them similar to functions.
$ alias foo='seq 3 | '
$ foo cat
1
2
3
Functions are functionsCan't do that without eval, which is another can of worms. Aliases are fine
Working example:
pzoppin() {
printf 'echo is for torrent scene n00bs from %s\n' "$*"
trap "printf '%s\n' <<< \"$*\"" RETURN EXIT SIGINT SIGTERM
}
export -f pzoppin
echo -e 'irc\0mamas donuts\0starseeds' \
| xargs -0 -n 1 -I {} /usr/bin/env bash -c '
echo hi
pzoppin "$*"
echo byee
' _ {}
The above will fail miserably without the magic incantation: `export -f pzoppin'
Why'd they design an otherwise perfectly usable, mapless language without default c-style global functions? :) [ "${BASH:-}" ] && shopt -s expand_aliases
[ "${ZSH_VERSION:-}" ] && setopt SH_WORD_SPLITFor instance -- why would you use "alias" when you can make a function? The syntax is a little weird with functions, but it's a lot more clear what's going on.
The same goes for "test" vs the seeming magic of [ where it seems like [ is language syntax (it's a single character!) when in fact ... it's just another executable that communicates with logic evaluation like anything else (like grep or false).
1. Aliases can work with the callee scope.
alias MY_VAR_MODIFIER='local foo=bar'
MY_VAR_MODIFIER () { local foo=bar; }
Calling the alias by the name will set the callee's variable foo, while calling the function does nothing (local foo is local to the function and never leaves scope).It also works similarly for working with the set ($@). You can do `set --` stuff and it works on the scope of the callee.]
Aliases on most shells also don't need to be fully valid _before_ expansion. You can alias a compound command:
alias foreach='for EACH'
foreach in $MYVAR #perfectly valid for most shells.
Only ksh93 will complain about it, it requires aliases to be complete valid shell programs.Finally, alias calls don't appear in xtrace (set -x). Only the final expansion will appear.
TL;DR aliases in scripts work a lot like macros.
Supply check=True and the script will barf on subprocess failure. Another useful upgrade.
But realistically it's rarely that simple and even when it starts that simple it will grow to not be.
The downvotes are a very disappointing attitude.
I agree that some work is better suited to a real programming language, however the driving force isn't the problems you speak of, which are trivial, it's when the logic/control flow of the overall problem becomes more complex.
It will try to prevent you. It isn't perfect though, and whitespace errors are only the tip of the iceberg.
Shellcheck doesn't tell you to enable pipefail for example, so there's a huge foot-gun.
Pipefail itself is kind of impossible to use correctly anyway.