4 ms·
After 15 years, I still struggle to test if a string is empty in shell languages. Do I use square brackets, double square brackets, equal sign, double equal sig
by buchanae 8y ago
After 15 years, I still struggle to test if a string is empty in shell languages. Do I use square brackets, double square brackets, equal sign, double equal sign, test -n, set -q, wtf mate? Do I need to wrap my string variable in double quotes? single quotes?
Fish looks great, and I'm going to give it a try, but I ran into these same old shell scripting issues within 2 minutes of trying to configure my prompt, which is a bummer. Took me 10 minutes (I'm ashamed to say) to end up at `if test -n "$git_branch"` (double quotes are critical).
I'll be excited when someone invents a shell that feels natural in this respect. Perhaps the nature of shells and commands makes this impossible? Or are we just stuck in a box?
- Groxx 8y agosometimes I wonder if "native" support for regexes would help this, or if it would just be another instance of https://xkcd.com/1171 https://xkcd.com/1171 regexes describe this sort of thing quite concisely and IMO a fair bit more readably than e.g. bash's string replacement syntax, which looks like "${var#"${var%%[![:space:]]*}"}" when you want to do the equivalent of s/^\s*(.*?)\s*$/\1/
- naniwaduni 8y agoIt wouldn't even be another standard; it'd just be another incompatible implementation with its own quirks to be worked around.
- Groxx 8y agoyeah, the wide variance in regex engines would definitely not be a positive quality :|
- duckerude 8y agoIt feels a bit more natural once you've bent your mind enough to understand what the shell is doing. The trick is that `test` and even `[` (which is essentially another name for `test`) are ordinary commands, that exist as stand-alone binaries as well as identical-behaving built-ins. They masquerade as syntax, but they're really not. You can even call them from other, non-shell languages: >>> from subprocess import run >>> run(('/usr/bin/[', '-n', '', ']')) CompletedProcess(args=('/usr/bin/[', '-n', '', ']'), returncode=1) >>> run(('/usr/bin/test', '3', '=', '3')) CompletedProcess(args=('/usr/bin/test', '3', '=', '3'), returncode=0) That means that they're not allowed to do anything to variables, because the variables are inside the shell. `test` doesn't see `"$git_branch"`, it only sees the content of the variable. Per the normal rules, `"$git_branch"` is an empty string iff $git_branch is empty or unset. Leaving the quotes off can do unexpected things, though a lot less so in fish. Using single quotes means you get a literal string, without any substitution. You're just looking for an empty string anyway, so you might as well use the equality operator instead of digging through the 18 (!) unary flags prescribed by POSIX. So I'd write either `[ "$git_branch" = "" ]` or `test "$git_branch" = ""`. Some implementations support `==` as another way to write `=`, but `=` is standard. This modularity makes the shell simpler, but it's not exactly sane. I think that providing `[` was a mistake, because it doesn't look like a command, but maybe having `test` as a command is better than having special expression syntax just for these cases.
- faho 8y agoThere are a few misfeatures in `test`, though. For instance, one way to use it is test somestring to test if "somestring" is empty. POSIX mandates that test with exactly one argument succeeds iff that argument is a non-empty string, to allow that. Fish's test is POSIX-conformant. Now, that means that test -n is true! Which is also triggered for test -n $var if $var has 0 elements. This is a problem and should be improved.
- CameronNemo 8y agoalways quote your variables. POSIX won't change this soon, or likely ever.
- buchanae 8y agoThanks for taking the time to explain the details. If we were to start with a clean slate, could we come up with something natural while still having a clean design with respect to commands? Would it be worth it? The fact that those details haven't sunk in after more than a decade points to an opportunity for a better design, I think. For example, I can pick up Go, Java, Perl, PHP, JS, Nim, etc and memorize the if-statement details in about 5 minutes. Whether or not anyone would use such a shell, I don't know.
- deleted 8y ago[deleted]
- aerique 8y agoI don't know, but I just use fish for interactive use and write shell scripts using #!/bin/sh.