the '''http://en.wikipedia.org/wiki/Bourne_shell%|%Bourne Shell''' is one of the two predominant [Unix shells]. ** Reference ** [http://en.wikipedia.org/wiki/Bourne_shell%|%Wikipedia]: [http://www.in-ulm.de/~mascheck/bourne/%|%The Traditional Bourne Shell Family], Sven Mascheck, 2001-10-07 - 2014-05-03: [http://pubs.opengroup.org/onlinepubs/9699919799/idx/shell.html%|%Shell Command Language], [http://pubs.opengroup.org/onlinepubs/9699919799/%|%The Open Group Base Specifications Issue 7], 2013: [http://pubs.opengroup.org/onlinepubs/009695399/utilities/sh.html%|%sh - shell, the standard command language interpreter], [http://pubs.opengroup.org/onlinepubs/009695399/%|%The Open Group Base Specifications Issue 6], 2004: ** Implementations ** [http://heirloom.sourceforge.net/sh.html%|%The Heirloom Bourne Shell]: ** Variants ** Modern variants of the Bourne Shell include ash: [bash]: [ksh], by [David Korn]: a popular Bourne-compatible shell which is also available on [Microsoft Windows%|%Windows]. zsh: ** Load or Generate a Tcl [List] ** Here are some shell functions to generate a Tcl list from a sequence of values, and to load a Tcl list into an array. They're handy, among other things, for storing and loading structured data. ======none #! /bin/env bash : ${TCLSH:=tclsh} #generate a Tcl list from a sequence of arguments #example: mylist=$(tcllist one two three '{' ) tcllist () { "${TCLSH[@]}" - "$@" <<-'EOF' proc main {argv0 argv} { puts -nonewline [lrange $argv 0 end] } if {[catch { main $argv0 [lrange $argv[set argv {}] 1 end] } cres copts]} { puts stderr $copts puts stderr $cres exit 1 } EOF } #load a Tcl list into an array #example: tcllist_arr myarray '{one two {three four} five}' tcllist_arr () { eval $1'=()' while read -d $'\0'; do eval $1'[${#'$1'[*]}]="$REPLY"' done < <( "${TCLSH[@]}" - "${@:2:$#}" <<-'EOF' proc main {argv0 argv} { set list [lindex $argv 0] foreach item $list { puts -nonewline $item\0 } puts '' } if {[catch { main $argv0 [lrange $argv[set argv {}] 1 end] } cres copts]} { puts stderr $copts puts stderr $cres exit 1 } EOF ) } ====== Conversely, here is a Tcl procedure to translate a string containing a sequence of words quoted in Bourne shell syntax into a list It handles arbitrariily-complex shell syntax, including command substitution, so watch out for [injection attack%|%injection attacks]. ====== proc shtotcl {value {sh bash}} { set script "printf 'puts \[lrange \$argv 1 end]' | \$1 - $value" return [exec $sh -c $script - [info nameofexecutable]] } ====== Example: ====== shtotcl $env(LDFLAGS) ====== A more updated version of this code might be found at [ycl%|%ycl::format::sh::shtotcl]. ** Why Bourne Shell Is not Fit for Programming ** It is well-known that [csh] is not fit for programming. Bourne shells also do not rise to the occasion. One big issue is their scoping rules. In the following example, `$i` in the second function interferes with `$i` in the first function: ======none f1 () { local i for ((i=0 ;i<10 ;i++)); do echo $i f2 done } f2 () { for ((i=0 ;i<5 ;i++)); do #do something useful : done } f1 ====== ---- [PYK] 2015-08-04: In my opinion, one of the biggest reasons not to write programs in the Bourne shell language is that subshells swallow errors. In the following example, `hello` is not expected to print because the interpreter should exit when the unknown variable, $x is referenced, and indeed it doesn't: ====== /bin/env sh set -u echo $x echo hello ====== In sh scripting, however, it's extremely common to run commands in a subshell and collect their output. In the following example, even `hello` does print even though the shell is configured as before: ====== /bin/env sh set -u echo $(echo $x) echo hello ====== Programming in a dynamic language is already adventurous enough. At least choose a sane dynamic language like Tcl. Beware the ''This is going to be a smallish script so I'll just write it in sh'' trap. [EMJ] 2015-09-02: Well, that's what they do (assuming you meant ====== #!/bin/env sh ====== both times and ''env'' really is in ''/bin'' - not on my system it isn't), but the second one rather misses the point, since it uses command substitution which just runs whatever and substitutes its '''output''' so that you actually get a blank line in the above case - after the error message about an undefined variable from the subshell, but the return status of the command (subshell or anything else) is not checked, only the output (nothing in this case) is used. That's how it works, nothing is propagated up from sub-processes. And yes, shell programming (any shell) is way too complicated, but if you're not allowed to use anything that's not already on the system, or that nobody else in the organisation knows... ---- [dbohdan] 2015-09-02: I think there's truth to the following [PYK] quote from the [Tcl chatroom]. How Tcl and the POSIX shell respectfully go about performing substitution is what makes one a serious competitor to [Lisp] and the other difficult merely to [http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html%|%loop through a list of file names] with. |` 04:20 < pooryorick> And the secret sauce of Tcl compared to sh is that Tcl doesn't rescan substituted values. `| |` 04:20 < pooryorick> In retrospect, I think that's Ousterhout's most remarkable contribution. `| ** See Also ** [Playing Bourne shell]: <> Unix Shells