10 ms·
Alternatively you can use the newer (and highly recommended) bash syntax that is also quote safe: $ a=1; b=1; c='!'; d='!' $ [[ $a = $b && $c = $d ]]
by fooblat 6y ago
Alternatively you can use the newer (and highly recommended) bash syntax that is also quote safe:
$ a=1; b=1; c='!'; d='!'
$ [[ $a = $b && $c = $d ]] && echo true
true
For anyone writing bash scripts today I would avoid the old test/[ functions entirely.
- dataflow 6y agoIt's always fun to assume everyone is running Bash until your Mac's zsh or your Ubuntu's dash (or whatever) choke on your script a few times. When this happens enough times you eventually reconsider...
- linkdd 6y agoThat's what shebangs are for: #!/usr/bin/env bash If it's not there, it will fail. I expect every script with `#!/bin/sh` as shebang to be POSIX shell only.
- dataflow 6y ago> If it's not there, it will fail. Until your users/colleagues source it into another shell, or copy-paste some part of it into their shell/Makefile/Bazel/other script... and then either you feel sorry for them, or you laugh at them and blame them for burning themselves and trashing their system. (Hopefully your choice didn't cause their files to get wiped. Unless you think they deserved it for daring to paste your code somewhere else, I guess.) The world isn't perfect.
- linkdd 6y agoThis problem is not exclusive to bash, try copy-pasting python 2 code into python 3. Or ES2020 code in a browser. Or ASM z80 into an x86 program. When you're copy-pasting, you should be aware of what you're copying, and where you're pasting it. Surely, no domain in IT is idiot-proof.
- dataflow 6y ago> This problem is not exclusive to bash, try copy-pasting python 2 code into python 3. No, it is highly exclusive to Bash actually. In Bash, even one-character mistakes have a high potential to cause catastrophic damage. Just splitting or globbing on the wrong character can wipe your filesystem. As well as issues like these, where your string being '!' suddenly causes the command to be interpreted entirely differently. And Bash has modes that keep going when there is an error so it's not like you'll even know you've encountered an error or get any kind of visible crash + stack trace necessarily. It just keeps trashing everything further and further. These are extremely wildly different from Python. > Surely, no domain in IT is idiot-proof. I would love to know what happens when you say this to a user who pastes your Bash in zsh. Do you tell them your code isn't idiot-proof? Is everyone who ends up running Bash in zsh for some reason or another an idiot?
- linkdd 6y agoIf you're not doing `set -euo` and if you run your scripts as root before testing them, you're asking for something wrong to happen. EDIT in response to your EDIT: My users get either: - a tar.gz archive - a binary - a docker image - an helm chart - a POSIX shell script (very rare) Then they can use any method they want to deploy it. You want your software to be portable? You have to put in the work to do it. If you expect your users to know better (assume they ARE idiots), again, you're asking for something wrong to happen.
- DonHopkins 6y agoNo, if you're using a language that requires you to perform some obscure incantation like "set -euo" before running your scripts, you're asking for something wrong to happen. Blame the disease, not the symptom.
- dylan604 6y agoif your pedantic enough to use "set -euo", you're going to add it to the script and not make a user set it first.
- acdha 6y agoIf people copy-and-paste complex shell scripts without testing, you’re going to have a bad day no matter what you do. The solution is to work on better practice, use of shellcheck, rewriting complex logic in Python, etc. since that’ll pay dividends in so many other ways.
- dolmen 6y ago> Until your users/colleagues source it into another shell The intersection of people knowing the "source" command and not knowing what is a she-bang or the difference between sh and bash is quite small.
- dataflow 6y agoSo what is your point here? I'm hallucinating when I see people do this?
- cjaybo 6y agoAre you suggesting that leaving off the shebang line makes these types of mistakes less likely? That makes no sense.
- skinner927 6y agoIf I copy Python 2 code into Python 3 it’s not gonna work right either. What’s your point?
- fooblat 6y agoI've been seeing this argument for decades and yet I've never run into any issues like you describe. When I write a bash script it is for my use or in my production system. In either case I call bash explicitly (/usr/bin/env bash) so the script will work correctly or not at all. Rarely do I have a project where there is a requirement to write a "run anywhere" script but if it were I would stick to posix.
- dataflow 6y agoThere are more people in the world than you. You might do everything perfectly; other people won't. Especially users who have yet to learn about these pitfalls. If you haven't run into this, either you're lucky enough that it doesn't apply to your situation, or you haven't become aware of it or tried to pay attention to it. I know I've seen people try to run Bash in their Mac's zsh (not necessarily deliberately either; some programs just run the default shell) and watched it crash and burn. I'm not condoning it, I'm saying it happens whether you and I like it or not, and you can either blame the victim (which I guess wouldn't be the first time I see this happen), or you can do something about it.
- fooblat 6y agoAm I understanding correctly that your point is that we shouldn't write modern bash scripts because some number of untrained people will have problems by accidentally misusing the scripts (wrong interpreter, blind copy/paste, etc). Is that a correct summary? To me this sounds like saying we shouldn't have powerful tools like chainsaws because every year some people without safety training use them wrong and hurt themselves.
- dataflow 6y agoNo, that's just an exaggerated caricature of what I'm saying. I'm only saying you should avoid using modern things needlessly. This means, don't do it when the POSIX-compliant syntax also serves your needs. e.g., don't do [[ -f "$foo" ]] when you could just as easily do [ -f "$foo" ]. And if you do need to use Bash-specific features, make sure it's safe enough that foreseeable misuses will fail safely. Or when that's not possible, try to mitigate it somehow (maybe with a comment, or by putting in some extra dynamic checks, or other solutions you can think of). And this goes for other things too, not just Bash. Probably outside programming too.
- raffraffraff 6y agoAlso, bash on Mac is shitty. I've run into problems with it before (can't remember exactly what it was) so we've reversed it: our shell scripts are written in zsh, and we just ensure that zsh installed everywhere.
- dataflow 6y agoOh yeah that too, that's another whole can of worms I forgot to bring up, thanks for mentioning it.
- jcynix 6y agoBesides that bash has its problems with array variables. Unless I switch to one of the "real" scripting languages, I use zsh too and start my scripts with if [[ -n "$BASH" ]] ; then echo $0: use zsh, not bash exit 1 fi Earlier on I used the more compact [[ -n "$BASH" ]] && { echo $0: use zsh, not bash; exit 1 } But bash chokes on that with a syntax error
- Izkata 6y agoThe syntax error is on a required semicolon. Put one after the "exit 1": [[ -n "$BASH" ]] && { echo $0: use zsh, not bash; exit 1; }
- simias 6y agoAs always my take on this is that if you don't care about portability, why even bother with bash? My rule of thumb is that if your script becomes too complicated that you find POSIX sh limiting, it's probably a good hint that you should rewrite it in a proper programming language. Bash scripting is an anti-pattern in my opinion, it's the worst of both worlds since it's neither portable nor that much better than POSIX.
- fooblat 6y ago> it's the worst of both worlds since it's neither portable nor that much better than POSIX Writing modern bash using the updated syntax, it is easy to make robust scripts and the syntax around things like quoting is simple and consistent. It seems odd to me to suggest that one should either stick to the old brittle /bin/sh syntax or not use bash at all. It has it's place in the world and it should be done the modern way. You'll find 10s of thousands of lines of bash in the kubernetes repo and all the files I checked are written using modern bash syntax. There must be a reason they choose bash for these parts. Of course, in any case everyone should use the tools they like and find most suited to the task at hand.
- skj 6y ago"there must be a reason" hahahahahaha
- scbrg 6y ago> There must be a reason they choose bash for these parts. Kubernetes is a Google creation. Google mandates bash for shell scripts: https://google.github.io/styleguide/shellguide.html#s1.1-which-shell-to-use https://google.github.io/styleguide/shellguide.html#s1.1-whi...
- lanstin 6y agoBecause it's everywhere anyone cares about and isn't some weird thing like zsh or Lord forgive us tcsh. Also all of these modern are basically fancy wrappers around bash scripts. Even dockerfiles is just a way to run some shell commands at image build time and other shell commands at launch time. Much less puppet or ansible or user-data.sh ....
- fanf2 6y agoThe [[ builtin is a ksh feature copied by bash. POSIX includes [[ and ]] in its list of reserved keywords but doesn't specify their behaviour.
- inetknght 6y ago> For anyone writing bash scripts today I would avoid the old test/[ functions entirely. I think it's better said that anyone writing bash scripts today should always pass their script to shellcheck.net. It can even be installed locally in case sharing the script online is undesired. Shellcheck will not only look for problems in the script but it will also usually provide some background about how the problem is a problem and a suggested workaround or solution.
- WaxProlix 6y agoYou can also use shellcheck[1], which has saved me from pushing numerous potential bugs into production. https://www.shellcheck.net/ https://www.shellcheck.net/
- nik_0_0 6y agoThis article appears to be discussing how to handle this case from within said shellcheck :)
- gnubison 6y ago> Alternatively you can use the newer (and highly recommended) bash syntax that is also quote safe Well, mostly: $ a=1; b='*'; c='!'; d='*' $ [[ $a = $b && $c = $d ]] && echo true true $ [[ $a = "$b" && $c = "$d" ]] && echo true $ From the bash(1) manpage: > When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below under Pattern Matching, as if the extglob shell option were enabled. POSIX syntax is more consistent and more portable: $ [ "$a" = "$b" ] && [ "$c" = "$d" ] && echo true $
- 1vuio0pswjnm7 6y agoI would avoid using bash for writing scripts (i.e., non-interactive use). There are better shells for scripting, like the one most Linux distributions are using, derived from the default shell in NetBSD, derived from the Almquist shell. The thing I miss most when using Linux is the default NetBSD shell. It has the speed of dash plus command line history.
- jolmg 6y ago> that is also quote safe Depends on what you mean by quote safe. Quotes aren't redundant: $ d='*' $ [[ foo = $d ]]; echo $? 0 $ [[ foo = "$d" ]]; echo $? 1