Insufficiently known Posix shell features
apenwarr.ca
apenwarr.ca
Also,
${CC:=gcc}
is only more readable than: [ -z "$CC" ] || CC=gcc
if you know what that syntax means. There are a ton of syntax in bash/zsh to modify varables inside of the ${} construct. I usually have to look them up every time that I see them, even when I was the one the wrote the original code. I would say that more people know the 'test' syntax than the ${:=} syntax. > 3. You can assign one variable to another without quoting
This is somewhat annoying, because something like this: command="ls -l"
$command /path/to/dir
doesn't work. It tries to run a command called "ls -l" which probably doesn't exist. Passing that to exec will work, though. A more common example of this issue would be trying to build a command-line in the shell script before executing it, you might have base level of options: base_options="-l -d --debug=1"
command $base_options $opt1 $opt2
But $base_options gets passed as a single parameter to command.${CC:=gcc} is a special case of syntax, but one of the points in the article is: as with any programming language, you should actually learn it so you can write better code. If people start using this one, it won't be any lesser known than any other weird sh syntax. The other variants (=, -, :-, etc) the article recommends against anyway.
As for your comments on #3, both of your examples are untrue; they work fine in a POSIX shell. Try it. (They fail in zsh, when zsh isn't in "sh compatibility" mode, so perhaps you're using that. Try switching it to sh compatibility mode.) Either way, those examples aren't actually related to point #3 in the article.
> Use $() and be happy, and I recommend never touching
> the backquotes again.
Any clue why the 'sh' filetype in Vim highlights $() as an error unless it reads "#!/bin/bash" on the first line of the file? (Zsh actually has its own filetype, but unfortunately no folding built-in support like the sh filetype) There's gotta be a reasoning behind that. Maybe $() isn't POSIX, but unofficially standard b/c most shells support it?[ Note (IIRC) in vim shell filetypes are like this: sh=(sh, bash, ksh) zsh=(zsh) csh=(csh, tcsh) ]
> Either way, those examples aren't actually related to point
> #3 in the article.
They were sort of related in that I was talking about the shell implicitly quoting the contents of the variable. I was just pointing out a different context where (I believe) that it also does something similar. > They fail in zsh, when zsh isn't in "sh compatibility" mode,
> so perhaps you're using that.
I ran into issues with that a few years ago, and then steered clear of using things in that way. I may well have been using zsh at the time as I was using it for a while before switching to bash, and then back again to zsh (and I didn't keep notes on that timeline).http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu...
In general, beware of trusting the people who wrote your editor instead just trying it to see if it works :)
Also, OpenBSD's pdksh seems to stick quite closely to POSIX shell features, it's probably a good test environment.
> In general, beware of trusting the people who wrote your editor instead just trying it to see if it works :)
That runs the risk of encountering an additional feature of the current shell compared to POSIX, this is very much the source of all bashisms: just trying to see if it works.
I agree that "just see if it works" isn't a good portability strategy if you only test one shell. But the idea is to get as many shells as possible and try them all, or (as redo does) to write a script that accepts only shells with all the expected features. Blindly assuming POSIX compliance is a dangerous way to go, since there's no guarantee that it's in a shell just because it's in the spec.
I'll grant you that using a feature that's both in POSIX and in all the shells you test is the best option, though :) $() is in both categories.
That said, there are many shells, that don't support $() and other random POSIX shell features. In fact, assuming that POSIX = portable is asking for trouble, because most systems actually aren't entirely conforming to POSIX (even when they are certified as being so). Another problem with relying on POSIX for portability is that in some places, the specification is worded in way that suggest one meaning and actually means something else (see for example behavior of glibc when operating on already terminated threads, which is POSIX compliant, but that this is correct is not immediately obvious from the specification).
All the features in the article are tested by redo, so at least in your redo scripts, you can assume those features are available. Maybe someone can generalize the "redo-sh" feature somehow.
edit: and then I read http://news.ycombinator.com/item?id=2271004 further below, which makes Tcl (or python, or ...) look even better.
to what end?
Shell is the least common denominator.
$ { read A; read B } < <(echo "C"; echo "D")
$ echo $A
C
$ echo $B
D
See http://tldp.org/LDP/abs/html/process-sub.html for more information.By default? Windows (heh). And most Unix servers don't come with bash by default. Though I think you can install it on most anything, it is not a good idea to change the default root shell on Unix servers.
That being said, OSX and Linux have Bash as the default shell. If that's all you deal with then go ahead and learn Bash (and the other GNU utilities) instead of POSIX sh. Unless you're an admin there's no point in being so pedantic.
This is neither serious nor modern, nor particularly operating :-P
> And most Unix servers don't come with bash by default
Most Unix systems are either Mac, Linux or BSD boxes, all of them provide bash (it may be a tiny little bit more complicated under BSDs). I will risk saying the list of recent Unixes (as in "with versions published in the last 5 years") that don't provide bash is limited to 3 items.
Perhaps four. IRIX 6.5.30 was launched in late 2006.
edit: maybe five. Tru64 had a launch (patches) in 2010. Guess I should have said "major version"...
$ mkfifo /tmp/pipename
$ (echo "C"; echo "D") >/tmp/pipename &
$ { read A; read B } </tmp/pipename
$ echo "$A"
C
$ echo "B"
D
$ rm /tmp/pipename
Using named pipes does introduce the issue of cleaning them up afterwards, but if you're managing this yourself you can do that manually. I'm still investigating fun alternative solutions to this problem.