rm -rf "$STEAMROOT/"* set -eu
on top of your bash scripts -- execution will stop on errors (non-zero retvals) and on undefined variables.set -e and set -o pipefail really should have been the default, rather than an opt-in.
Consider /tmp/test.sh:
set -o pipefail
yes foo | head
$ bash /tmp/test.sh >/dev/null
$ echo $?
141I've collated other mishandling of closed pipes at: http://www.pixelbeat.org/programming/sigpipe_handling.html
http://mywiki.wooledge.org/BashFAQ/105
disagrees and refers to GreyCat's preference not to use -e at the bottom of the list of 'complications'.
You can use set -e, and turn it off (set +e) for code blocks and things that are problematic. He could also add '|| true', and you may be able to use colon to avoid point problems without turning everything off. These are edge cases and you can easily work around them if you an advanced user.
If you are not an advanced user then you should certainly use -e.
$ diff -u /tmp/a /tmp/b
--- /tmp/a 2015-03-24 08:33:00.021919797 -0400
+++ /tmp/b 2015-03-24 08:33:05.629963015 -0400
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
set -e
i=0
-let i++
+let i++ || true
echo "i is $i"
$ /tmp/a
$ /tmp/b
i is 1
$[[ "$VAR" ]] && rm -rf "$VAR/*"
I think most of these issues stem from the fact that most developers that write shell scripts don't actually understand what they're doing, treating the script as a necessary annoyance rather than a component of the software.
Anyways, that is not anything like other programming languages. Checking in that way is error prone and not really an improvement (nor equivalent to set -o).
[[ "$DAEMON_PATH" ]] && rm -rf "$DEAMON_PATH/*"
See what I did there? It's an rm -rf /* bug because "checking variables" is not the answer.In other programming languages, if an identifier is mis-typed things will blow up. E.g., in ruby if I write:
daemon_path=1; if daemon_path; puts deamon_path; end
I get "NameError: undefined local variable or method `deamon_path`"These issues do not always stem from bad developers. Bash's defaults are not safe in many ways and saying "people should just check the variable" isn't helpful here.
set -u
Man page quote: "Treat unset variables and parameters other than the special parameters "@" and "*" as an error when performing parameter expansion. If expansion is attempted on an unset variable or parameter, the shell prints an error message, and, if not interactive, exits with a non-zero status."
These bugs are indicative of Bash's design problems. Why is it used for init scripts? And don't even get me started on how Bash interprets filenames as part of the arguments list when using * (e.g. file named "-rf").
Say what you will about Powershell, but having a typed language that can throw a null exception is useful for bugs like these. The filename isn't relevant, and a null name on a delete won't try to clear out of the OS (just throw).
Not just scot free - during the Great systemd War of 2014 is was a talking point for the antis that using anything other than the pure, reliable simplicity of shell for service management was MADNESS!
That's not Bash. That's just... programs in Unix. Such is life when everything is stringly typed.
rm -r "${VAR:-var_is_not_set_so_please_fix_this_script}"
which substitutes the var_is_... if VAR is not set.BTW, I hate hate hate -f. It has two meanings: 1. 'force' the removal 2. ignore any error
I've seen an instance of this sort of bug in my sysadmin career that I remember. It was a Solaris patch which wiped a chunk of the system.
If you're suggesting using parameter expansion, at least suggest the correct one (i.e. one that will give a meaningful error message):
${parameter:?word}
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3...some real-world programming languages don't have undefined variables :)
Being the emptys string "" would work just as well.
2. set -e
3. type an invalid command or run one that returns non-zero
4. "crap, where did my shell go?"
The real answer is that this has not been the default in the time between shells being invented and this comment being posted, and so the squillions of lines of shell script out there in the wild keeping the world turning have not been written with this in mind. Making it the default now would break a lot of things.
With the benefit of hindsight, though, i would say that yes, this should have been the default in scripts. Oh well.
`echo /* `: /bin /dev /etc /lib ...
`echo /*/`: /bin/ /dev/ /etc/ /lib/ ...
`echo "/*"`: /*
`echo "/*/"`: /*/
If you try it with `ls`, you'll find that `ls "/* "` results in `ls: "/* ": no such file or directory`.Edit: Formatting.
[1] https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/issue...
There were some circumstances where if there was no cache_dir line configured, or if the cache_dir was a link or something, the details are very sketchy in my mind after so much time, but it would end up destroying /.
I'm guessing this is of that same nature.
Every time I've seen such a bug (honestly, not many), it was created when cleaning a temporary dir.
It looks like a bug in the init script; runnign it as squid's user wouldn't have triggered destroying the whole filesystem; likely just squid's config and anything under its /var.
Which is what happens when you have every daemon writing their own PID handling code, running as root, in a language whose interpolation rules nobody really understands.
It is quite possible to have the script for PID handling be written once, and imported as needed.
It looks like a bug in the init script...
Ha ha ha ha ha ha ha.
This because what it provides it rapid spin up of containers and VMs, while everything talks to each other via APIs and DBUS.
But this rapidity also leads to issues with field repairs and debugging.
"Everyone" is adopting it because the Linux money is in web servers/services.