dash/ash
dash/ash
Posted Oct 1, 2014 20:58 UTC (Wed) by chutzpah (subscriber, #39595)Parent article: Bash gets shellshocked
Some minor investigation finds that mksh appears to be an alternative that supports a reasonable number of these sorts of these features, while still being relatively lightweight.
Posted Oct 1, 2014 21:04 UTC (Wed)
by josh (subscriber, #17465)
[Link] (2 responses)
Posted Oct 2, 2014 13:51 UTC (Thu)
by CChittleborough (subscriber, #60775)
[Link]
Posted Oct 2, 2014 14:52 UTC (Thu)
by gwolf (subscriber, #14632)
[Link]
$ diff -u <(cmd1) <(cmd2)
is way easier and clearer than
$ F1=`tempfile`
Of course, it makes sense to include this bashism in your scripts. And, of course, that'd make your scripts depend on bash.
Posted Oct 1, 2014 22:13 UTC (Wed)
by wahern (subscriber, #37304)
[Link] (23 responses)
There are various ways to handle lists of things in the POSIX syntax. One lesser-known way is by using the "set -- [...]" construct, which resets your local argument vector. A more common method is using read(1).
Many times people use Bash-specific features simply because they don't understand or care about POSIX syntax. I'd love to see a count of hands of shell programmers who have ever read the POSIX documentation for the shell. See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html. The framed version is much easier to read: http://pubs.opengroup.org/onlinepubs/9699919799/
But as josh said, if you're writing software that really requires juggling lots of data, why keep the shell? Why not just switch to Perl, for example? I'd be surprised if Perl wasn't installed by default on at least as many vendor platforms as Bash. Unless your goal is sheer portability or simplicity, using the shell doesn't make any sense.
Bash in particular is hardly more light-weight than Perl. The Bash and Perl interpreters are comparable in size. Compare them to dash.dash/ash
Bash can be a big win for many scripts
Useful bashisms
$ F2=`tempfile`
$ cmd1 > $F1 &
$ cmd2 > $F2 &
$ diff -u $F1 $F2
$ rm $F1 $F2
dash/ash
$ ls -sh /bin/bash
1000K /bin/bash
$ ls -sh /usr/bin/perl /usr/lib/libperl.so.5.18.2
12K /usr/bin/perl 1.6M /usr/lib/libperl.so.5.18.2
$ ls -sh /bin/dash
120K /bin/dash
And, no, bash is not statically linked in the above. Assuming all the developers of those projects are equally good programmers, how many bugs do you think lurk in bash compared to dash? Are arrays really worth all that code surface? Perl might be bigger, but I'd bet Perl has fewer bugs just because the language grammar is simpler and more regular--go figure. And, yes, using the shell is fraught with quoting problems. Historically that was not only because the shell syntax mixes code and data in subtle ways, but because the shells themselves often had parsers which caused unexpected behavior (sometimes a bug, sometimes a "feature"). Using Bash features may address the former to some small extent, but it certainly doesn't address the latter.
Posted Oct 1, 2014 22:36 UTC (Wed)
by Jandar (subscriber, #85683)
[Link] (5 responses)
One global array is hardly a replacement for the bash arrays. Btw the set builtin is well-known.
> A more common method is using read(1).
Do you mean managing arrays in multiple tempfiles and reading (+ writing with ugly escapes) on any usage? Appalling.
The omission of arrays in posix-shell is the major reason for me to ignore it and use bash.
Posted Oct 2, 2014 14:23 UTC (Thu)
by nix (subscriber, #2304)
[Link] (3 responses)
Posted Oct 3, 2014 9:48 UTC (Fri)
by Jandar (subscriber, #85683)
[Link] (2 responses)
typeset -a Options Files
How do you prepare (with correct quoting) a dynamic argument-vector without arrays? All other methods are ugly and error-prone beyond any acceptable limit.
Posted Oct 17, 2014 11:12 UTC (Fri)
by mgedmin (subscriber, #34497)
[Link] (1 responses)
paths[${#paths[*]}]="$1"
Rewriting this to use +=() will make my scripts a bit saner.
Posted Oct 17, 2014 12:02 UTC (Fri)
by mathstuf (subscriber, #69389)
[Link]
Posted Oct 3, 2014 19:30 UTC (Fri)
by wahern (subscriber, #37304)
[Link]
foo() {
printf "$# -> $*\n"
printf "$# -> $*\n"
Also, per POSIX: "Positional parameters are initially assigned when the shell is invoked (see sh), temporarily replaced when a shell function is invoked (see Function Definition Command), and can be reassigned with the set special built-in command."
Obviously this isn't a complete substitute for arrays, neither alone nor in tandem with other alternatives.
But my point is that people use Bash features without understanding the alternatives, and without appreciating the cost of Bash. Bash is a great interactive shell. But if you're serious about shell programming, one should learn POSIX syntax, as well as sed(1), awk(1), and the nuances of other utilities. This isn't hard because the POSIX documentation is infinitely more clear and concise than implementation documentation. A good way to practice is with Solaris, because Solaris' utilities are often annoyingly anachronistic (e.g. grep doesn't even have a recursive mode), but dash isn't a bad place to start, either. And when you do choose to use extended functionality, do so knowingly, having assessed the costs and benefits.
Posted Oct 1, 2014 23:16 UTC (Wed)
by SEJeff (guest, #51588)
[Link]
Posted Oct 2, 2014 8:31 UTC (Thu)
by ibukanov (subscriber, #3942)
[Link] (11 responses)
Perl is not particularly safer with syntax that is similar in complexity to Bash. Besides, the shellshock comes not from the syntax but from a badly designed Bash feature that could be provided for "convenience" just as well in Perl or Python or JavaScript under node.js.
Posted Oct 2, 2014 9:41 UTC (Thu)
by niner (subscriber, #26151)
[Link] (7 responses)
So I'd argue that it is much easier to program safely in Perl than in Bash.
Posted Oct 2, 2014 15:54 UTC (Thu)
by ibukanov (subscriber, #3942)
[Link] (6 responses)
I want to repeat that Shellshock has nothing to do with programming style of Bash scripts. It comes from a badly designed and implemented feature of the Bash interpreter that is written in C. Perl runtime could just as easily provide a similar "feature" affecting any Perl script, strict or not. For example, can you with certainty assert that Perl interpreter has no bugs related to reading of environment variables that could trigger execution of arbitrary Perl code?
Posted Oct 2, 2014 17:31 UTC (Thu)
by dskoll (subscriber, #1630)
[Link] (3 responses)
Perl runtime could just as easily provide a similar "feature" affecting any Perl script, strict or not.
But it doesn't. Well, with one exception: Setting PERL5DB will make perl execute arbitrary Perl code, but only if it has been invoked with the "-d" command-line flag which says to run under a debugger, and no Perl script uses that flag.
Perl makes environment variables available in the %ENV hash, but certainly doesn't try to interpret them as Perl code (modulo the single exception above.)
Posted Oct 5, 2014 20:15 UTC (Sun)
by alankila (guest, #47141)
[Link] (2 responses)
Thankfully, none of this is even close to as bad as what bash did.
Posted Oct 7, 2014 14:35 UTC (Tue)
by dskoll (subscriber, #1630)
[Link] (1 responses)
PERL5LIB and PERL5INC are not used in taint mode. Bash really needs a taint mode.
Posted Oct 7, 2014 17:31 UTC (Tue)
by mathstuf (subscriber, #69389)
[Link]
Posted Oct 2, 2014 21:25 UTC (Thu)
by flussence (guest, #85566)
[Link] (1 responses)
It's had that feature for decades: 2-arg open() will happily interpret any filename passed to it containing a "|" prefix or suffix to mean a command pipe, and helpfully give the rest of the string to the shell to run. The same function is also used internally to pass filenames in ARGV into the magic <> line-iterator.
Posted Oct 3, 2014 11:23 UTC (Fri)
by dskoll (subscriber, #1630)
[Link]
2-arg open() will happily interpret any filename passed to it containing a "|" prefix or suffix
That's a little different from the bash bug. It requires the programmer to write a script that doesn't handle user-input safely. It's also stopped in taint mode.
The Bash bug doesn't require any action on the part of the script writer; it happens before your script even has a chance to do anything.
Posted Oct 2, 2014 14:59 UTC (Thu)
by gwolf (subscriber, #14632)
[Link] (1 responses)
I do argue (see my above comment) for the utility of some sorts of bashisms, particularly those that help forked process' control and quoting (another favorite of mine is to use $() instead of ``, as it's *way* clearer. I won't argue for using Bash when you use arrays and local scopes — That's a clear indication you should switch to a real programming language. One that, between many other things, separates parsing/compiling from executing, because your program will most likely be complex enough to warrant it!
But yes, people complain about Perl being write-only. Bash constructs and mindset are way worse than Perl.
Posted Oct 2, 2014 15:38 UTC (Thu)
by madscientist (subscriber, #16861)
[Link]
As others have pointed out, if you want to write bash scripts that's fine and it's trivial to do: just start your script with #!/bin/bash. If you want to write POSIX shell scripts, start your script with #!/bin/sh. If you use #!/bin/sh and you use bash-isms, your script is simply wrong.
Posted Oct 9, 2014 11:30 UTC (Thu)
by ssokolow (guest, #94568)
[Link]
That sort of thing is why I encourage friends who are launching child processes to do their scripting in Python using the subprocess module. They really did a great job on designing its API... especially when paired with various other modules already part of stdlib. Apparently someone's also ported it to ruby though, unfortunately, it's not part of stdlib there and I don't know whether shlex is also available. Plus, of course, convenience functions like
Posted Oct 2, 2014 13:49 UTC (Thu)
by mbunkus (subscriber, #87248)
[Link] (3 responses)
As much as I love and use Perl it doesn't have several things that I find extremely useful for scripting: set -e, set -x and zsh's globbing functionality. I don't know of an equivalent for either of the »set«s, and especially -e is truly a very effective way of preventing accidental mishaps.
Then again: for me it's a question of when to switch from zsh to Perl, not from bash to Perl. zsh can do a lot of things that bash cannot, therefore I do get further via shell scripts than I would with bash; meaning the gain of switching from bash to Perl is usually higher than for zsh to Perl.
Posted Oct 3, 2014 9:42 UTC (Fri)
by cortana (subscriber, #24596)
[Link] (2 responses)
Posted Oct 1, 2014 22:25 UTC (Wed)
by debacle (subscriber, #7114)
[Link]
Posted Oct 2, 2014 6:05 UTC (Thu)
by Karellen (subscriber, #67644)
[Link]
Posted Oct 2, 2014 6:19 UTC (Thu)
by ptman (subscriber, #57271)
[Link]
Posted Oct 2, 2014 11:00 UTC (Thu)
by eru (subscriber, #2753)
[Link]
Posted Oct 4, 2014 7:03 UTC (Sat)
by tomgj (guest, #50537)
[Link] (1 responses)
Posted Oct 9, 2014 10:59 UTC (Thu)
by Tet (guest, #5433)
[Link]
dash/ash
dash/ash
dash/ash
Options+=("$option1")
Files+=("$file1")
$UseVerbose && Options+=("-v")
$UseSecondFile && Files+=("$file2")
command "${Options[@]}" -- "${Files[@]}"
dash/ash
dash/ash
dash/ash
set -- A B C
}
set -- 1 2 3 4
foo
printf "$# -> $*\n"
dash/ash
dash/ash
dash/ash
Perl does not mix program code with data.
Perl has a taint mode that catches many cases of missing input sanitation.
Perl's system() function only ever invokes /bin/sh if the given command contains shell metacharacters and supports the system PROGRAM LIST form that never ever invokes a shell (it uses exec()) at all and avoids many errors with missing parameter quoting.
dash/ash
dash/ash
dash/ash
dash/ash
Bash needs an overlay:
dash/ash
_____________________________________________
/ It looks like your script is over 100 lines \
\ long; did you mean to write this in Perl? /
---------------------------------------------
\
\
.::!!!!!!!:.
.!!!!!:. .:!!!!!!!!!!!!
~~~~!!!!!!. .:!!!!!!!!!UWWW$$$
:$$NWX!!: .:!!!!!!XUWW$$$$$$$$$P
$$$$$##WX!: .<!!!!UW$$$$" $$$$$$$$#
$$$$$ $$$UX :!!UW$$$$$$$$$ 4$$$$$*
^$$$B $$$$\ $$$$$$$$$$$$ d$$R"
"*$bd$$$$ '*$$$$$$$$$$$o+#"
"""" """""""
dash/ash
dash/ash
Bash and Perl
Bash and Perl
dash/ash
shell=True
shlex.split()
, os.path.expanduser()
, fnmatch.filter()
, glob.glob()
modules from the Python standard library.env
argument makes it easy to call a subprocess with a sanitized environment.cwd
argument avoids the need for cd
ing in os.system()
or doing an os.getcwd() os.chdir()
dance.subprocess.call()
, subprocess.check_call()
, and subprocess.check_output()
integrate nicely with the mix of try
/except
/finally
and os.walk()
I already recommend for that sort of scripting.dash/ash
dash/ash
Either I write dash or I use Python
dash/ash
dash/ash
Adding a selection of the more scripting-friendly bashisms to dash might not bloat it. For example, the array feature looks simple: one-dimensional only, integer indices, and dash already supports evaluating integer expressions in the context of $((expr)) expansion. Of course, identifying which are the most useful extensions (without taking all bash features) is a problem.
dash/ash
dash/ash
The thing about moving to dash or ash for shell scripts is that some of the "bashisms" are truly useful features.
Okay but that doesn't mean that "sh" needs to be bash. The scripts that require bashisms can use bash explicitly by name, leaving sh to be a more minimal implementation of the POSIX shell.
dash/ash