4 ms·
Test your square brackets
- theandrewbailey 10mo agoNow do [ ... ] and [[ ... ]] I'm still not sure when to use one or the other. I use double brackets by default until something doesn't work.
- stabbles 10mo agoDouble brackets are less portable. For example musl linux does not come with bash by default, and your script fails. When unsure, use shellcheck.
- a3w 10mo ago[[ is built in, so "test[" as an /usr/bin artifact never exists? (What to call that proposed program, test2, or test[ ?)
- duskdozer 10mo agoYou mean shellcheck will detect when single brackets won't be enough? I've also just defaulted to double because I never really looked into it
- stabbles 10mo agoYeah, if you set the shebang `#!/bin/sh` (which is portable), shellcheck will complain about double brackets. It also helps you do quoting correctly when using single brackets.
- duskdozer 10mo agoI see. I've always just used `#!/usr/env/bin bash`. I wonder if there's a directive to hint at incompatibilities without changing it? I'll have to see. And this isn't meant snarkily - why should I care if my scripts are portable? I've worked on a number of different devices and types but have seemingly always had access to bash.
- PhilipRoman 10mo ago[[...]] is non-portable and has an extremely quirky corner case with variable expansion in arithmetic contexts, what's not to love?
- ndsipa_pomu 10mo agoI'm intrigued - any info on that? I personally use ((...)) for arithmetic tests and [[...]] for all other tests as I just target new versions of BASH and don't care much about POSIX compatibility.
- PhilipRoman 10mo agoThis is completely safe: [ "${payload}" -eq 42 ] This can evaluate arbitrary code: [[ "${payload}" -eq 42 ]] Here is one example of a malicious payload: payload='a[$(touch /tmp/pwned)]'
- ndsipa_pomu 10mo agoThanks. Now I need to figure out whether (( payload == 42 )) is safe.
- ndsipa_pomu 10mo agoIt appears not.
- account42 10mo agoIt also does wildcards though, with POSIX you'll need a case statement for that.
- nickjj 10mo ago[[ ... ]] supports regex comparisons and lets you combine multiple conditions in a single bracket group using && and || instead of remembering to use -a / -o. I usually default to [ ... ] unless I need features that double brackets provide.
- ndsipa_pomu 10mo agoUse ((...)) for arithmetic tests and [[...]] for other tests. [...] is for POSIX compatibility and not as useful as [[...]] though I don't remember the specifics.
- zzzeek 10mo agoyeah, if [ is a command in /bin/ what is [[ ?
- SAI_Peregrinus 10mo agoA builtin part of the shell, just like `if` and `then` and `fi`. Not all shells have `[[`, the one that doesn't which people unknowingly run into most is probably `dash` as used by Alpine Linux. POSIX doesn't require `[[` in a shell, BASH & Zsh support it but others often don't.
- zzzeek 10mo agoright so "[" is a file in /bin, "[[" is implicitly part of the shell, so that's as bad as I thought
- xp84 10mo agoIf shipping something that must run on sh, check your life choices and use [ - otherwise [[ is better. Honestly though I’ve been much happier since I stopped writing anything complex enough to have conditionals in Shell. Using a real scripting language like Ruby, Python, even PHP or Perl if you know them, is better. In the Ruby case I just use `%x( … )` when I need to run shell commands (there are some things shell does great like passing pipelines of text through 5 programs) and let the logic part be in Ruby.
- reactordev 10mo agoThe ultimately sad part was the professor in a Sun OS machine. In a corner with no where to go, giving demerits because his bash was older than he realized. Reminds me of my college professor that claimed you don’t have to close HTML tags (some you absolutely do) and I proved that you do. Not all of them, but most of them. (Netscape Navigator Days)
- jonhohle 10mo agoIt doesn’t have anything to do with bash (though modern bash may use a built in for `[`). He don’t have the `[` program (usually linked to `test`).
- reactordev 10mo agoWhich is why later versions of bash have a builtin… Precisely because those older systems didn’t link to it! So my comment still stands.
- deleted 10mo ago[deleted]
- Someone 10mo ago> Precisely because those older systems didn’t link to it! Not to speed up bash scripts? Launching a process for simple if statements such as those checking whether a file exists is fairly expensive.
- reactordev 10mo agoUgh, which is why it became a builtin… Ya’ll are tracing the same logic of the 90s here.
- Sharlin 10mo agoWhy do you think the prof even used bash? I highly doubt his ancient SunOS machine had a GNU toolchain. `test` and `[` are both POSIX, but if there was no `/bin/[` I doubt the shell in question (original Bourne? Some proprietary Sun shell? Who knows) had it built in either.
- Wowfunhappy 10mo ago> When I was a young, green, university student, I was forced to use test(1) as the only true way to do testing in shell scripting. […] Yeah, I was also forced to not use semicolons as they were evil (according to my professor, any comment unneeded!). The author’s professor clearly went overboard, but doesn’t this entire anecdote demonstrate the value of teaching it this way? Having green students call the `test` binary provides more insight into how UNIX operates, and gets them using a UNIX mindset. They can discover the syntactic shortcuts later.
- ogogmad 10mo agoHmm. What if we replaced the whole of bash with the contents of /bin?
- Wowfunhappy 10mo ago…you always need some sort of shell to call the binaries, don’t you? I do think it makes sense to have beginners use `sh` instead of `bash`.
- jcynix 10mo agoOh, "once upon a time" I did set emacs to be my login "shell" and emacs can call other binaries via execve, handle sub processes, etc. Worked as expected. Getting a Linux or Unix system to boot without a proper shell would be another complication, so a system completely without a she'll? I expect that to either be easy nor useful.
- stabbles 10mo agoNowadays [ is a builtin. The subprocess for a simple branch would be excessive overhead.
- MontyCarloHall 10mo agoIt is indeed a builtin, but `/bin/[` still exists for compatibility reasons! $ which [ /bin/[ $ type [ [ is a shell builtin The same is true for the `test` command: $ which test /bin/test $ type test test is a shell builtin
- stabbles 10mo agoRight, that's also a good reminder that the builtin `command -V` is typically what you want whenever you use not-always-builtin `which` ;)
- xg15 10mo agoSo if you really want to troll someone, you can put them in quotes. if "[" "$foo" "==" "bar" "]"; then ...
- ndsipa_pomu 10mo agoHere's Greg's Wiki about the difference between [, [[ and test https://mywiki.wooledge.org/BashFAQ/031 https://mywiki.wooledge.org/BashFAQ/031
- jcims 10mo agoReminds me of my rather memorable introduction to special characters invoking functions, seeing this dastardly little quip in the email signature of someone in a mailing list (circa '95 or so). :(){:|:&};: My curiosity piqued, I pasted it into the shell on my terminal in a pure example of FAFO. The poor little Sparc 5 I was using ground to a halt over the course of about ten seconds. The reboot was as hard as the lesson. xD
- dcminter 10mo agoI have this printed on a sweatshirt - it saddens me a little that people who get it are so few and far between these days :'(
- jcims 10mo agoI have it on a tshirt. Pretty sure most people think it's just an emotional rant in emoji form.
- mitchell_h 10mo agosuch nostalgia. There was a time when you could tell a fair bit about someone if that was in their email signature.
- meindnoch 10mo agoContext: https://www.cyberciti.biz/faq/understanding-bash-fork-bomb/ https://www.cyberciti.biz/faq/understanding-bash-fork-bomb/
- jcynix 10mo agoAnd especially the ulimit command mentioned, which is mostly unknown to folks nowadays, it seems.
- ogogmad 10mo ago> The reboot was as hard as the lesson. I'm confused. What happened on reboot?
- joshstrange 10mo agoIn college I took a database class, it was pretty basic overall as I had been playing with MySQL for a few years at that point. On the final exam I got a 90/100. The test was 10 questions that just had you write SQL to answer the question. I got all the queries 100% correct... except... I didn't put a ";" after each query. On a written test. I'm still a little bitter about that.
- MrJohz 10mo agoI had a course on natural language processing with Prolog, and the first third of the exam was just evaluating Prolog expressions and figuring out what syntax errors had been made. This of course took so long that everyone spent at least two thirds of the time on that one portion... It was a weird course, though. Because we spent so long learning Prolog, the second half of the course was really rushed - lots of learning about English grammar and syntax trees, and how you could model them in different ways, and then the last lecture was just "oh, by the way, here are all the ways this doesn't work and is a complete dead end - your exam is on the 14th". IIRC there was a part two to the course, but I think it clashed with something I was more interested in so I never took it. It was cool to learn Prolog, but I wish it had been a whole course on just Prolog and actual present-day use-cases, as opposed to this weird half-and-half course about an approach to NLP that even back then wasn't being pursued with much enthusiasm.
- andrewcl 10mo agoThe Objective-C folks probably are chuckling their square brackets send messages.
- esafak 10mo agoTo me the salient part is that he had an exam on shell scripts?!
- Normal_gaussian 10mo agoI did my degree in 2012-2015; and we had a mandatory first year course on *nix, which IIRC included a test on shell scripting. Its not really theoretical or applied CS, but it is a core skill for meaningfully doing applied CS.
- CGMthrowaway 10mo agoI've been spending too much time researching home improvement and thought this was going to be about deck-building.
- meisel 10mo agoThe real solution is that as soon as you need square brackets, switch to a better language than bash
- layer8 10mo agoWhy would you need square brackets if test is the same?
- mcc1ane 10mo agohttps://github.com/anordal/shellharden/blob/master/how_to_do_things_safely_in_bash.md#how-to-write-conditions https://github.com/anordal/shellharden/blob/master/how_to_do...
- HarHarVeryFunny 10mo agoWhoa! /bin/[ as a binary looking for it's own "]" closing bracket! What a nasty syntax hack! I wonder what the motivation was for doing this rather than just implementing test expression support directly in the shell? I just tried and bash also accepts some other odd filenames in place of "[", so you can do: ln -s /bin/test "-" ln -s /bin/test "$" And use either of these in place of "[" (assuming they are on your path). Of course they still expect the closing "]" since that requirement comes from /bin/test. It's an interesting way to extend bash in a confusing way! You could write a "$" utility that did something else entirely, perhaps looking for a "closing $" too, then write something like: if $ args $; then fi
- 1f60c 10mo agoI also love argv[--argc]. Evil genius. And it's fully legit (from the draft C standard, 5.1.2.2.1, § 2 "Program startup"): > The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination. https://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf https://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf [pdf]
- projektfu 10mo agoHere is the part of the test.c source from V7 Unix: main(argc, argv) char *argv[]; { ac = argc; av = argv; ap = 1; if(EQ(argv[0],"[")) { if(!EQ(argv[--ac],"]")) synbad("] missing",""); } argv[ac] = 0; if (ac<=1) exit(1); exit(exp()?0:1); } So, if the professor was missing the "[" command, they were missing a link. More likely, they had a weird orthodoxy about using "test" instead of "[" because reasons. One good reason to use "test" instead of "[" in a Bourne shell control statement is if you are running a list of commands between "if" and "then", and the test is the last part of the list. Another good place to use "test" is if you are not in a control statement and you are just setting $?. Edit: EQ() is defined as: #define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0)) char *tmp;
- jcynix 10mo agoThe [[…]] built-in test version was introduced in Peter Korn's korn shell, ksh88 IIRC. As where various other modernized notations like array variables, process substitution or $(command) as a much more readable version of the backquotes version. https://docs.oracle.com/cd/E36784_01/html/E36870/ksh88-1.html https://docs.oracle.com/cd/E36784_01/html/E36870/ksh88-1.htm... While learning the Bourne shell as acstudent, I was rapidly lured by csh and then tcsh, but Tom Christiansen's pamphlet https://everything2.com/title/csh+programming+considered+harmful https://everything2.com/title/csh+programming+considered+har... and (or?) the appearance of Paul Falstad's Z-Shell saved me ;-0
- Normal_gaussian 10mo agoI knew that `[` was notionally the same as `test`, but had never 'checked'. I just assumed `[` was a built-in that conformed rather than them actually being the same. So I very much enjoyed following along with the article, first seeing that `ls -il /bin/test` and `ls -il /bin/[` are at different inodes, then md5summing and seeing they are different, getting concerned, then the article revealing that is the case now (I'm trusting rather than verifying about the separate builds). I was then very satisfied to recall that `[[` is a built-in (as `[[` isn't portable between all shells).
- deleted 10mo ago[deleted]
- JuniperMesos 10mo agoI don't like bash, and this kind of esoteric, hard-to-remember syntax is a big reason why. Software developers and computer users should want their shell to be easy to use and reason about, just as they reasonably want this from their general-purpose software development languages. bash is a UNIX legacy tool from the 80s that lingers on in software written today because it's part of the POSIX standard (well, sh, which is close enough), and because generations of developers on UNIX-like systems can be assumed to be familiar with it. I don't think this is a good thing, and I would like to see active efforts to replace the use of bash with better, more-modern scripting languages that provide an easier-to-understand more-reliable experience for users.