15 ms·
test, [, and [[ (2020)
- neverrroot 3y ago[[ is bash only. If you know you’ll only use bash, use it. For details, the article is nice.
- nerdponx 3y agoThat is, test and [ are specified by POSIX and usually are physical binaries (but might also be masked by shell builtins). Whereas [[ is not specified by POSIX and usually only exists as a shell builtin.
- shmerl 3y agoWhy would you not use Bash (unless you are using completely different shell like Fish explicitly?). It feels like some completely archaic concern to target the minimal common shell denominator.
- driggs 3y agoBecause Apple switched the default macOS shell from the GNU-licensed `bash` to the BSD-licensed `zsh`?
- bgm1975 3y agoApple switched when bash switched from GPL2 to GPL3 which they didn’t like. The older bash is still available.
- toast0 3y agoAccording to the interwebs, zsh became default with Catalina in 2019 [1]; ten years after bash 4 was released with gpl v3 or later. Also, the interwebs suggest Apple used to use tcsh as the default shell[2]; I don't know when they changed that, but it may have been after bash 4 released? (Thanks, 10.3 was in 2003, so several years before the license changed) [1] https://www.theverge.com/2019/6/4/18651872/apple-macos-catalina-zsh-bash-shell-replacement-features https://www.theverge.com/2019/6/4/18651872/apple-macos-catal... [2] https://news.ycombinator.com/item?id=18853318 https://news.ycombinator.com/item?id=18853318
- masklinn 3y agobash became the default shell in 10.3. tcsh was the default before then.
- masklinn 3y ago> Apple switched when bash switched from GPL2 to GPL3 Apple just didn’t update. It took them years to finally switch to switch to zsh. > The older bash is still available. Aside from it being bash (a great reason not to use it as far as I’m concerned) it’s now a 17 years old version of bash.
- toast0 3y ago> Aside from it being bash (a great reason not to use it as far as I’m concerned) it’s now a 17 years old version of bash. I thought people liked macOs for its vintage feel? Remember a time when computers could only render a single menu bar in a fixed location, feel the experience of SYN floods, run a version of bash that is old enough to vote in the next presidential election.
- mkesper 3y agoHonestly this is such a waste of time every time I have to argue with developers about installing up to date homebrew (or whatever) versions of the coreutils that I wish Apple would simply DELETE all these ancient versions of tools from MacOS. As a bonus, homebrew does not offer --with-default-names any more and some tools (like make) are posted into different paths so you need to add your own symlinks or add multiple paths to your PATH.
- LambdaComplex 3y agoNot installed by default on BSDs. Sometimes not installed in minimal environments, e.g. where BusyBox is all you have available. Maybe not installed by default on Unixes? Not sure
- loa_in_ 3y agoHonestly, installing bash into environments seems like less work than avoiding it. It's not hard to do.
- JohnFen 3y agoWhen your script will be running on customer machines, you often don't have the luxury (and sometimes it's not technically possible because it doesn't exist) of installing bash into the environment.
- DonHopkins 3y agoTime to find better customers.
- loa_in_ 3y agoWhat prevents you from shipping bash with your solution?
- JohnFen 3y agoThese scripts are often used to install the application, so that introduces a chicken-and-egg situation. How can I install bash before running the installer? Also, we'd have to build and maintain our own just for platforms missing it, which increases cost and complexity. It's easier, cheaper, and less error-prone just to use a minimum common denominator that runs on everything. Additionally, when your customers have strict policies regarding how applications are approved for use and have to vet and test everything you give them, it's best practice to avoid installing anything that you can avoid installing. Doing that minimizes the effort and hassle for both the customer and the developer.
- mikem170 3y agoBash seems to be about as archaic as sh. I write my shell scripts in sh, because it comes with every unix-like os by default. I know that bash has more features, but I've never really missed them. I switch from sh to perl for more complicated tasks. To each their own, right?
- 15457345234 3y agoThis to me seems like good practice, it's better to use a 'real' programming language when you're crossing the boundary from 'script' to 'program' Shellscript has way too many idiosyncracies and weirdnesses that would have been beaten out of a proper programming language by now. (I know that talking about weirdnesses is amusing in relation to perl which also has a whole armload of them.)
- hnbad 3y ago> This to me seems like good practice, it's better to use a 'real' programming language when you're crossing the boundary from 'script' to 'program' PowerShell would like a word with you.
- account42 3y agoPowerShell's problem is that it is a real programming language, which makes it less suitable for a shell.
- hnbad 3y agoI was half-joking but the downvotes were to be expected in a conversation about Linux shells.
- usrbinbash 3y agoNo, power shells problem is that it cannot decide whether it's a programming language or a shell REPL, and ends up doing both badly. The syntax is too cryptic (and far too verbose) for a REPL, and too "shell-y" for a PL. bash, for all its many many many flaws, is quite clearly a REPL first, PL second.
- yjftsjthsd-h 3y agoIIRC Debian uses dash as /bin/sh because it's faster (execution speed) than bash.
- emmelaich 3y agoThat's like using a horse instead of a mule. Just not worth it. Move away from the whole equine world and use a real programming language.
- yjftsjthsd-h 3y agoEh, there are things that shell is really good at, and there are things that other languages are good at. I will grant that shell is best for glue code; my personal heuristic is that I stick to POSIX sh, and if that hurts then I take that as a sign that I should be considering moving to Python or whatever. But avoiding it completely strikes me as a poor choice, because for the "glue together separate programs and manipulate files" tasks that it's meant for, it's really good and IMO everything else still falls short.
- aidenn0 3y agoIIRC, /bin/sh on Ubuntu defaults to dash
- eikenberry 3y agoThat is from Debian and all child distros inherit it by default, not just Ubuntu.
- jabl 3y agoIf you want to nitpick, it was first done by Ubuntu and then later upstreamed into Debian (from which other child distros, as you correctly point out, inherit it).
- andrewshadura 3y agoIn fact, only dash is supported as /bin/sh on Debian and Ubuntu.
- JohnFen 3y agoI've worked on several modern projects that needed to be able to run on a wide variety of Unix platforms, several of which didn't have bash. Writing for the common shell denominator was important, not archaic.
- shmerl 3y agoStill sounds archaic that it's a problem today that needs to even be addressed.
- jtafurth 3y agoI wouldn't say it's an archaic problem, an example I can think of is writing scripts for infrastructure running minimal docker images where you want to keep the image size to a minimum, you would usually need to support both bash and other shells. Embedded applications come to mind as well.
- csydas 3y agoit’s contextual as most things. need to actually use and work on the machine? use whatever shell you want to make your life easier. need a script to run on many different systems and/or need to write a script to be managed automatically by a service account? probably you want a shell with syntax that is guaranteed to be the same on all your systems.
- dredmorbius 3y agoWriting Bourne-compliant scripts ensures maximum portability. As many here have noted, bash isn't universally available, with another possible issue being OpenWRT devices. Stock/base images tend to use a Bourne-compatible shell, not full Bash. Though the latter's installable through opkg, for sufficiently small devices (typical of consumer kit), you simply won't have the space to install them. There's also the slight PITA that Apple's OSX ships with a very old, pre-GPLv2 Bash, out of licensing concerns. (Apple is phenomenally averse to GPL-based code, much as some *BSDs are, such as OpenBSD.) And if you're dealing with legacy systems (which tend to be extraordinarily and stubbornly persistently legacy), you'll often find that either bash isn't present or is quite dated. I freely confess that I tend to write fairly recent-feature bash scripts myself by default, and appreciate many of the newer features. But if and when I am writing portable code, I'll go back to Bourne-compatibility. But when writing system level code, an appreciation for standards and the very long tail of legacy standards and the limitations they impose is in fact a large component of professional maturity.
- bregma 3y agoIt's archaic if you're a dabbler, a hobbyist, an academic, or a junior dev who lacks the experience of shipping software into the wild. For the rest of us, we have learned the hard way, sometime repeatedly, portability and adherence to published standards matters.
- shmerl 3y agoThat doesn't make it less archaic if anything today still has this problem.
- usrbinbash 3y agoWell, I am a professional who administrates quite a lot of systems. And they all run bash. They all understand `[[`, they all understand `~=` If any of them did not, then I'd ensure they do. Yes, shells that do not support modern bash syntax ARE archaic, no matter who sits in front of the screen. And same as I consider it part of my job description to keep systems up to date with security patches, I consider it part of my job to ensure they use modern versions of contemporary and widely used scripting languages and shells. And that includes bash. So no, relying on features that can be expected on a modern system is not a sign of inexperience. Same as a dev is within his rights to not write his python code under the assumption that it has to talk with a python 3.4 interpreter, he is within his rights to not expect a system that only knows sh.
- re 3y agoWell, zsh too :) https://zsh.sourceforge.io/Doc/Release/Conditional-Expressions.html https://zsh.sourceforge.io/Doc/Release/Conditional-Expressio...
- bgm1975 3y agoAnd ksh (ksh88 & later)
- dredmorbius 3y ago"bash only" typically refers to "bashisms", that is, bash features not present in the plain Bourne shell (or Bourne-compatible interpreters such as dash). The fact that other shells (such as zsh) may include those features ... is beside the point of writing universally compatible shell scripts. Confirming my facts for this comment, #TIL that "dash" is the "Debian Alquist Shell", that is, Debian's "ash" shell: <https://en.wikibooks.org/wiki/Guide_to_Unix/Explanations/Choice_of_Shell https://en.wikibooks.org/wiki/Guide_to_Unix/Explanations/Cho...>
- emmelaich 3y agoAlways use [[ zsh and ksh have it; in fact I'm pretty sure it originated with ksh in 1988 or earlier.
- OmarAssadi 3y ago> Always use [[ While zsh, bash, mksh, ksh93, probably others have it, sure. But many don't -- and not totally irrelevant ones either. Debian's default, dash, for example, does not support `[[`. IMO, unless you're writing something like shell-specific dotfiles, avoid non-POSIX features. It's usually pretty trivial to avoid them, especially if you're willing to call other mandated commands like awk, etc. But often, with a bit of creative thinking, most non-standard features can be replicated with some combination of `set`, separate functions and/or subshells. Shell scripts, in general, have dozens of footguns, are pretty much impossible to statically analyze, difficult to make truly robust, and many of the shells themselves -- e.g., bash -- have huge, borderline inauditable codebases. I can think of a dozen reasons not to write shell scripts. Yet still, there is incredible value in the fact that some form of POSIX-compliant/compliant-enough shell can usually be found on most systems. All of that value goes out the window, though, the moment you start relying on non-standard features.
- massysett 3y agoDon’t worship at the altar of portability. There is real cost to portability, as it forces you to cater to broken implementations and to not use features that may be very useful. Also, it can be difficult to ensure compatibility with systems that you don’t test on, so true portability requires having different systems to test on. Sometimes all those costs are necessary for the task at hand. For example, the whole point of GNU Autoconf is that it runs on a wide variety of systems. On the other hand, many programs are for in-house or personal use and will not run on obscure systems. The cost of writing for portability simply might not be worthwhile in these situations. And that’s ok, notwithstanding some conventional wisdom of “always try to be portable.”
- arp242 3y agoDepends what you're writing. If you're writing an installer script or whatever that's going to be run on $many computers that you don't control: sure, it's probably best to go to the extra effort to stick with POSIX sh. But that's not most scripts. Most scripts are things that you run on computers you control. I just write things as zsh scripts because it's so much easier than bash (never mind POSIX sh). That's fine, because I can just install zsh. And actually, this often makes scripts more portable because you need to rely on external utilities a lot less.
- metadat 3y agoI've learned to only use [[ when I want to do a regex match, e.g. if [[ "${foo}" =~ ^bar$ ]]; then echo Yes; fi Otherwise, just stick with "test" or "[". 85,000 lines of bash and counting... Not saying bash is great, but it's still meeting my needs for a lot of stuff. Shrug.
- cvccvroomvroom 3y agoThat's a pointless example. [ "$foo" = bar ] && echo Yes For substring matches, [ and * globs are generally good enough. [ "$bar" = extra* ] && echo '$bar began with extra' Bash's regex dialect is primitive and rarely worth fussing over. For anything complicated, use another tool be it grep, awk, perl, or such. There are diminishing returns of obsessing over doing everything in bash when a complicated task demands more capabilities suitable to another tool with greater reusability, modularity, and intrinsic types.
- aidenn0 3y agoI thought regex inside [[ was the same as egrep?
- stephenr 3y agoIf you want to do (relatively) simple pattern matching in a posix-compliant way, `expr`[1] can match BREs, and even return a capture group. 1: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html https://pubs.opengroup.org/onlinepubs/9699919799/utilities/e...
- somat 3y agoAs someone who enjoys shell scripting I don't think I have ever used the "expr" command. this astonishes and baffles me because I used to read the man pages for fun, I even had a little script to pick a random page. So thanks a bunch for bringing it to my attention. My only guess as to why I am unfamiliar with the command is that perhaps younger me failed to figure out "expression" means regular expression. It only clicked this time because of your comment and the see also: re_format link at the bottom. http://man.openbsd.org/expr http://man.openbsd.org/expr
- shmerl 3y ago> And now for the final lolz. I’ve said above that these are the commands you use to evaluate expressions… but the shell also has expressions of its own via the !, &&, and || operators—all of which work on command exit statuses. It works for simulating very basic boolean expressions, but it gets ugly quickly if you need some more complex combos of NOT, OR and AND. I wish Bash had proper boolean expressions support.
- remram 3y agoWhat do you mean? Bash does have (), {}, !, &&, || What else do you need for "proper Boolean expressions support"?
- shmerl 3y agoI don't think you can assign boolean variables to boolean expressions, becasue there is no boolean type. Something like this won't work to become false: foo=true bar=false baz=$foo && $bar echo $baz Or even simply: foo=! $foo With numeric expressions, you can at least use $((...))
- emmelaich 3y agoYeh you'd have to do something like foo=true bar=false $($foo) && $($bar); baz=$? case $baz in 1) echo false;; 0) echo true;; esac It just ain't worth it.
- shmerl 3y agoYeah, that's very convoluted. It would be useful to have some context for boolean expressions, similarly how $((...)) works for numeric ones.
- account42 3y agoBut you can do foo=0 # true bar=1 # false [ $foo = 0 ] && [ $bar = 0 ] baz=$? echo $baz The syntax is a bit unusual coming from more modern languages, as is the use of 0 as true. But you can express whatever conditionals you want. Remember that C originally had no dedicated boolean type either. You could also use numerical expressions although I don't recommend it due to being even less readable (even more so if you have expression complex enough that you need to protect against overflow): baz=$((foo + bar)) // foo && bar baz=$((foo * bar)) // foo || bar
- jmmv 3y agoHey, original author here. Thanks for sharing this and making it rise to the front page! :) By the way, the title probably deserves a (2020) and it would be nice if "test" wasn't capitalized, because it actually refers to the command. Here is something related from 2021 that also touches on bash's [[ operator and that I think you might enjoy in this context: https://jmmv.dev/2021/08/useless-use-of-gnu.html https://jmmv.dev/2021/08/useless-use-of-gnu.html
- o11c 3y ago[[ is not really a builtin, it's fundamentally syntactical (but presumably uses a mostly-inaccessible builtin internally). Fun fact, `]]` is also a reserved word despite never being allowed in a context where reserved words matter. In some non-bash shells, the `function` keyword is needed to declare certain types of function. For make `$(shell)`, if you're building a lot of targets the performance difference can be measurable. Still, it loses in the nop case, so you should actually usually do `include` to trigger re-making. GNU is completely right to ignore POSIX, since POSIX is not useful for solving most real problems.
- account42 3y ago> In some non-bash shells, the `function` keyword is needed to declare certain types of function. In shells that aren't POSIX-compliant [0], maybe. In which case: yes, there are many wildly different scripting languages with REPLs. [0] https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...
- pmarreck 3y ago> since POSIX is not useful for solving most real problems POSIX, being a standard that can be tested, is at least a specification or agreement that can be met by multiple products to enable them to interact
- dang 3y agoOk, I've lowercased the leading 't'. We never do that but for this, ok :)
- yjftsjthsd-h 3y agoI actually thought [ and test were symlinks, but that might just be from Alpine Linux where they're both symlinks to busybox.
- somat 3y agoHardlinks actually, but who's counting? plus in real world usage you will hit the shell builtin anyway. ls -li /bin/\[ /bin/test 26016 -r-xr-xr-x 2 root bin 133256 Mar 25 2023 /bin/[ 26016 -r-xr-xr-x 2 root bin 133256 Mar 25 2023 /bin/test I have to admit I avoid "[" in my scripts, it is a weird hack trying to make a command look like syntax and this really bothers me for some reason.
- yjftsjthsd-h 3y agoNo, Alpine uses symlinks: $ docker run --rm -ti alpine / # ls -l /usr/bin/test /usr/bin/[ lrwxrwxrwx 1 root root 12 Sep 28 11:18 /usr/bin/[ -> /bin/busybox lrwxrwxrwx 1 root root 12 Sep 28 11:18 /usr/bin/test -> /bin/busybox / # ls -li /usr/bin/test /usr/bin/[ 495254 lrwxrwxrwx 1 root root 12 Sep 28 11:18 /usr/bin/[ -> /bin/busybox 495360 lrwxrwxrwx 1 root root 12 Sep 28 11:18 /usr/bin/test -> /bin/busybox / #
- figmert 3y agoThis is different. Alpine uses busybox, where everything is implemented in the busybox binary, thus everything is symlinked to it. In other distributions, test is a separate binary, and [ is a link.
- somat 3y agoInteresting... Doubly so because I thought busybox was a sort of linux crunchgen, A way to pack many independent executables into one to save space. With crunchgen at least, each executable name is then linked to the packed binary, that is, hardlinks. and the filesystem name is used to pick the correct code to run. Why did they go with softlinks? my guess... It can be moved across filesystem boundaries. Perhaps interference from cgroups? http://man.openbsd.org/crunchgen http://man.openbsd.org/crunchgen
- ridiculous_fish 3y agoThe biggest footgun in `[` and `test` is the single argument behavior. For example, you might attempt to check if a variable is nonempty like so: [ -n $FOO ] but if FOO is unset, it expands to nothing (as opposed to the empty string), so this is equvalent to: [ -n ] and POSIX requires that the one-argument form of `[` succeed if that argument (here, "-n") is non-empty. So this will falsely report that $FOO is non-empty. Remember to quote your variables!
- whateveracct 3y agoShellCheck your scripts!
- mr_toad 3y agoOr use set -u to fail early. Or use [ -n ${FOO-} ] which will replace the unset variable with an empty string.
- yjftsjthsd-h 3y agoPreferably you'd use set -u to avoid certain problems, and also keep using shellcheck for all the other things it can catch.
- LegibleCrimson 3y agoThat bottom one will also fail. The empty string is not treated as a shell word. You need double quotes.
- kazinator 3y agoThat is false. There is no difference between ${FOO} and ${FOO-}. Both disappear if unquoted, and FOO is unset or blank: $ printf "<%s>\n" alpha ${beta} omega <alpha> <omega> $ printf "<%s>\n" alpha ${beta-} omega <alpha> <omega> The form ${var-} form is useful for safely evaluating a variable that might be unset, when "set -u" mode is in effect, and for whatever reason we cannot just fix the script so that the variable is set.
- JNRowe 3y agochubot has written an interesting document¹ exploring more of the nuance with test/[/[[, and many of the other entries in that blog have intriguing explanations of the oddities of our shells(a random example²). ¹ https://www.oilshell.org/blog/2017/08/31.html https://www.oilshell.org/blog/2017/08/31.html ² https://www.oilshell.org/blog/2016/11/18.html https://www.oilshell.org/blog/2016/11/18.html
- deleted 3y ago[deleted]
- cellularmitosis 3y agoI stopped using [ a few years ago because ‘test’ reinforces the idea that this is just a command like any other, not syntax. Also, “man test” is much more pleasant that sifting through “man bash”.
- kazinator 3y agoYour comment makes no sense. GNU Coreutils has a "man [" as well as "man test" man page. Bash has "help test" for a quick cheatsheet. The [ command is very old; it was already present in Version 7 Unix in 1979.
- c0l0 3y agoParts of the comment make a LOT of sense actually, when you look at shell scripts written by the uninitated. Often times, I see constructs like while [ 1 ]; do ...; done which are a pretty clear indication of the author's misconception about the perceived nature of [ ], I think.
- kazinator 3y agoThe nice way to write that isn't any kind of test command but: while true; do ...; done There is never any reason to use test, other than portability to some broken environment that is missing [ but not missing test.
- cduzz 3y agoI have strong opinions about shell and they don't actually line up with the rest of the world... I believe that [ should never be used, only "test" because [ gives the illusion that the mechanism is some part of the language syntax when it is just another "program" (I'm including built-ins and functions in "program"). (if / || / && look at exit status; a program can't see the exit status of other things other than looking at the magic variable $? which is just another string once expanded; case looks at strings but doesn't operate based on exit status and doesn't set an exit status as part of the case ... esac operation; "programs" set an exit status) I also believe that [ / test should only ever be used for evaluating filesystem constructs -- test -f /dev/null and if you've got string evaluations use case. Unsurprisingly, most scripts make me itchy, and scripts that I write people find weird. [edited to add the explanation of "program" vs "syntax" opinion]
- cduzz 3y agoJoke's on me; that's the point of the article. I prefer, when writing in shell, to do this: if program then something else otherthing fi To emphasize that the thing after the if is just "look at the exit status of the last command before the then." if ls /tmp/goober test -d /tmp/goober echo "I'll always execute the then clause because echo will always return a 0 return code" then echo "this always gets run" else echo "this never gets run" fi because the "if" is just looking at the exit status of "echo". [edited to do code blocks]
- tpoacher 3y agolargely agree, but stylistically speaking I prefer the following: if ls /tmp/goober test -d /tmp/goober echo "I'll always love you or whatever" then echo "the grasshopper always jumps higher" else "never gonna let you down" fi i.e. all the commands line up at the 6th column, leaving the if/then/elif/else/fi stuff appearing on the 'margin', as it were. This works particularly well, visually, when nested ifs are involved.
- deleted 3y ago[deleted]
- stevage 3y ago> But if you know your script is going to be Bash-specific anyway, you are probably better served by using [[ unconditionally and consistently Honestly, I think writing a Bash script is just a terrible idea. Use a real language, and all of these nightmares go away. For me, lately, that's been Zx (which uses Node), but there are other fine choices too.
- LegibleCrimson 3y agoI agree. If a POSIX shell script serves your needs, use it. If it doesn't, you shouldn't be reaching for a more powerful shell, but an actual language. I'd reach for Perl before Bash, and I can't stand Perl.
- jmmv 3y agoBash is "real language" if you treat it as such. Yes, there are plenty of spaghetti scripts out there, riddled with global variables and full of side-effects, but if you write shell in a principled manner, you can solve some pretty big problems with ease, and you can write maintainable code. I wouldn't start new projects in shell, of course, but one area in which I think the shell shines is in writing integration tests for tools. More on this in a recent post I wrote: https://jmmv.dev/2023/10/unit-testing-with-shtk.html https://jmmv.dev/2023/10/unit-testing-with-shtk.html
- Joker_vD 3y ago> but if you write shell in a principled manner The same can be said about QBasic as well, honestly. And here's the catch: people who are inclined to write anything in a principled manner are likely the ones who'd write things in a principled language instead of e.g. shell. Or to put it in another way, if someone chosen to write in shell (or failed to consider an alternative, which also happens quite often), they're quite likely exactly the person to not write anything in a principled manner.
- jmmv 3y agoOftentimes, the constraints around what you have to do dictate what language(s) you can use. So you do what you can with them and you try to get the best out of them. https://jmmv.dev/2023/11/why-do-i-know-shell-and-how-can-you.html https://jmmv.dev/2023/11/why-do-i-know-shell-and-how-can-you...
- l0b0 3y agoSee https://mywiki.wooledge.org/BashFAQ/031 https://mywiki.wooledge.org/BashFAQ/031
- user261 3y agoI really didn't understand why the last if statement is confusing. Is it because when starting out with shell scripting one would usually assume that the [ is a part of the bash scripting language not just another program? If it's then I think I get it now. Otherwise please mention why it's surprising. Also, @author thanks for a nice article. was a good reed.
- computerfriend 3y agoEven if you don't know about [ as a binary, I still don't see how it's confusing. Seems like very normal bash to me.
- glandium 3y agoOne place where you learn not to use [ or [[, or be very careful about them is autoconf shell scripts (and that applies to more than `if`, like globs, sed, awk, etc.). Because square brackets are quote characters in autoconf. https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.71/html_node/Active-Characters.html https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/a...
- stn_za 3y agojs frontend dev masses ripping on bash here. lulz
- pavlov 3y agoWriting bash scripts seems like the ideal use case for Chat-GPT style programming. The programs are fairly short, examples are common in the corpus, and the syntax and execution model are so inscrutable that only a machine can pretend to understand what’s going on.
- croo 3y agoI already tried to customize my command line prompt with it. All the arcane colouring character decodings and random character escaping missions became a "put git branch names in parenthesis and make it cyan".
- db48x 3y agoWhat’s so arcane about `echo "$(tput setaf 6)cyan$(tput sgr0)"`?
- spullara 3y agoFor sure: https://gist.github.com/spullara/0fc3e88150f66179017b9aa1758d49d2 https://gist.github.com/spullara/0fc3e88150f66179017b9aa1758...
- rjblackman 3y agoyes, this is the best use case I have found for chat gpt. I've been automating away all of my little annoyances with powershell.
- wodenokoto 3y agoI had no idea [ was a program and the fact that it checks if the last argument is a closing bracket is kinda funny to me. But at least it explains why you need spaces on both sides of the brackets.
- deleted 3y ago[deleted]
- kqr 3y agoTaking the last point one step further, we can also dispense with the if block entirely: if [ a = b ]; then echo "Oops!" else echo "Expected; phew!" fi becomes [ a = b ] && echo "Oops!" || echo "Expected; phew!" I'm not sure how often you should do this but sometimes it comes in handy for things like [ "$debug" ] && echo "what's going on" >&2 to conditionally print debug output to stderr. ---- And the fact that the if block tests a regular command means we can also do things like if grep -q 'debug' /var/log/nginx/access.log; then echo "Debug request found!" fi ---- Something I have not yet bothered to figure out is whether I should write [ $(expr 1 + 1) -eq 2 ] && [ $(expr 2 + 2) -eq 3 ] or use the built in logical and of test: [ $(expr 1 + 1) -eq 2 -a $(expr 2 + 2) -eq 4 ] As long as performance is not a concern, I can see roughly equal reasons in favour of either.
- illo 3y ago> [ a = b ] && echo "Oops!" || echo "Expected; phew!" Not to be taken as a general rule though. I might be mistaken but I think that bash would parse the line as: ([ a = b ] && echo "Oops!") || echo "Expected; phew!" so if the command sequence after `&&` fails, then the code sequence after `||` is executed anyway: illo@joe:~ $ [ "a" == "a" ] && >/dev/full echo "strings match" || echo "strings don't match" -bash: echo: write error: No space left on device strings don't match illo@joe:~ $ This is different from the semantics of the `if` block: illo@joe:~ $ if [ "a" == "a" ]; then >/dev/full echo "strings match"; else echo "strings don't match"; fi -bash: echo: write error: No space left on device illo@joe:~ $
- deleted 3y ago[deleted]
- nwellnhof 3y ago> Something I have not yet bothered to figure out According to POSIX, the -a and -o binary primaries and the '(' and ')' operators have been marked obsolescent. See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html https://pubs.opengroup.org/onlinepubs/9699919799/utilities/t... under "Application Usage".
- darrenf 3y ago
- skrebbel 3y agoI'll never understand how there's a whole class of developers who absolutely despise JavaScript for acting weird when adding arrays to objects, but at the same time gladly write bash scripts and send each other articles about how [ is totally a program but ] isn't and that's all fine and dandy and in no way objectionable. EDIT: this comment is a bog standard HN middlebrow-dismissal and the blog post doesn't deserve this for to be the top comment. It was morning and I was grumpy. I can't delete it anymore so would appreciate some downvotes.
- hun3 3y agoYou can replace bash with JS. Scripting is their common application domain. Can you replace JS with bash, though? If the answer is "no," that means JS has applications (e.g., servers and web clients) that bash can't be used for. And they're saying JavaScript is bad at them. Bash is arguably worse, but it's usually not an option in the first place so you don't get to complain.
- mananaysiempre 3y ago> You can replace bash with JS Noo-ot really except in a Turing-tarpit sort of way. Like it or not, once learned (!) Bourne shell together with the traditional tools is a well-designed user interface and works even better for that than, say, Tcl[1]. Not an automation or scripting language, a user interface for all daily interaction. I would absolutely hate to manually sort through my files in JS, while in shell I can often do it faster than in a GUI file manager. And, of course, it’s also a fairly strong contender as a programming language in the paradigm of many pipelined imperative processes—probably because that paradigm remains largely unexplored. I can only maybe name Icon as a viable competitor, and Icon’s also very nice. (Python, no matter how “inspired” it is by Icon, has traded its command of streams for more mainstream ease of use.) By comparison, the old complement of parallellized JS build tools (Gulp? Grunt? I forgot, it’s been a while) always surprised me with how awkwardly it accomplished shell-script-equivalent tasks. To be clear, it’s not that Bourne shell is good and JS is bad. JS is a passable Fortran[2], while shell is at best a marginally functional one—there’s a reason Awk exists. But shell competes in categories that most other languages don’t even try to qualify for. [Yes, I know about rc. I happen to think rc’s focus on one-level lists of strings (incidentally shared by Jam, an attempt at a better make) is a mistake, and more consistent arbitrarily-nested quoting, giving a “stringy Lisp” in the vein of Tcl, would be the way to go.] [1] http://yosefk.com/blog/i-cant-believe-im-praising-tcl.html http://yosefk.com/blog/i-cant-believe-im-praising-tcl.html [2] http://conal.net/blog/posts/can-functional-programming-be-liberated-from-the-von-neumann-paradigm http://conal.net/blog/posts/can-functional-programming-be-li...
- xiaodai 3y agoR programmers be like: I still don't know when to use [ or [[. I just put a browser() then and test out the options
- deleted 3y ago[deleted]
- DonHopkins 3y agoSyntactic Syrup of Ipecac.
- hibbelig 3y agoI have recently written if some_command 1>/dev/null 2>/dev/null; then : # A-OK else here_is_the_code_i_actually_needed fi And it leaves me wondering if there is a way to “negate” the exit status of a command... (The command was “docker volume inspect VOLUME”, and in one place in my script I had to do things when the volume existed, and in other places I had to do things when the volume did not exist...)
- jeramey 3y agoYes, there is. To negate, just use ! as with many other languages. if ! command …; then do_needed_things fi
- ramshorns 3y agoHow does that work? It doesn't look like ! is a command or shell builtin, so I guess it's an argument to if.
- mkl 3y agoNo, it's part of the shell. Do "man bash" or "man sh", then search with "/\!". From man bash: "If the reserved word ! precedes a pipeline, the exit status of that pipeline is the logical negation of the exit status".
- hibbelig 3y agoAmazing! I've been writing shell scripts since the 90s and now I still learn something new. Thank you!
- xyzzy_plugh 3y ago> Some people insist that Linux distributions be called GNU/Linux, not just Linux. The reason is that, strictly speaking, Linux is just a kernel and, when you are using a Linux system, you are primarily interacting with the GNU userland. While I sympathize with that idea, I’m not the one to adopt the GNU/Linux name, in part because most Linux distributions today ship with software developed by many more vendors than just GNU. In this post, however, I use the GNU/Linux term because saying Linux alone would be unfair to Linux. Hear, hear!
- deleted 3y ago[deleted]
- jmclnx 3y agoInteresting, on Linux (Slackware, Debian), /bin/[ and /bin/test are not the same. But on NetBSD (and I assume others too, they are the same.
- 1vuio0pswjnm7 3y agoBourne has said there were proposals from the other users at Bell Labs to use braces or brackets with the "test" form, but these suggestions were not adopted. Bourne has said he did not like having to worry about missing braces in C, and there were no IDEs with automatic syntax-checking like today, and that is why he used macros to allow him to write in C using Algol-like syntax. That's what he said. Maybe that's why he decided not to braces or brackets with test. Personally, I prefer the "test" form to the "[" form. It's easier for me to read. Personal preference. To me, "[" looks uglier.
- gkfasdfasdf 3y agoInstead of trying to make a shell script portable across all different shells, I prefer to just use #!/bin/bash and not worry about it. (Of course bash version compatibility is a concern of it's own)
- MaryGab 3y ago[flagged]