8413
Comment: line breaks in long examples
|
206
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
= How to make bash scripts work in dash = This page is an attempt to list some of the most common bashisms, i.e. features not defined by POSIX (won't work in dash, or general `/bin/sh`). It probably won't be exhaustive. Note also we talk about "bashism" because this wiki is largely bash-centric but a number of these extensions work in other shells like ksh or zsh. == Syntax == || || '''Works in bash''' || '''Change to for dash''' || '''Comment''' || || defining functions || function f { echo hello world; } || f() { echo hello world; } || "function" is not defined by POSIX, only "name ()" is. In ksh both forms are present, but functions defined with "function" work slightly differently. || || case || `;;&` `;&` etc || None. Duplicate the case (use a function to avoid code duplication) || `;;&` `;&` in bash4 is not defined by POSIX. ksh93 has `;&` but not ``;;&` || || numeric C-like for loop || `for ((i=0; i<3; i++)); do`<<BR>>` echo $i`<<BR>>`done` || `i=0 ; while test $i -lt 3 ; do`<<BR>>` echo $i ; i=$(($i+1))`<<BR>>`done` || this syntax is not defined by POSIX. Present in ksh93. || || expand sequences || `echo $'hello\tworld'` || `printf "hello\tworld"` || `$' '` is not defined by POSIX and is bash-specific || || extended glob || `+( ) @( ) !( ) *( )` || not always possible, sometimes you can use several globs, sometimes you can use find(1) || not defined by POSIX. Present in ksh. || || select || `select` || some ideas: implement the menu yourself, use a command like dialog || not defined by POSIX. Present in ksh. || == Expansions == * Brace Expansion, eg `{a,b,c}` or `{1..10}` is not defined by POSIX. Both forms are present in ksh93, and the first form in older ksh. * The `<( )` and `>( )` process substitutions are not defined by POSIX, but can be simulated with FIFOs: instead of `foo <(bar)`, write `mkfifo fifo; bar > fifo & foo fifo` (this is basically how process substitution is implemented on OSes that don't have a mechanism like `/dev/fd/` to refer to unnamed pipes with filenames). It is present in ksh93. == Parameter Expansions == List of expansions not defined by POSIX: * `${name:n:l}` -- if the variable contains no newlines, you can use `$(printf '%s\n' "$name" | cut -c $n-$((n+l-1)))`. If there are newlines, you can use `$(printf %s "$name" | dd bs=1 skip=$n count=$l 2>/dev/null)`, but printf may report a (harmless) broken pipe if the variable contents are large enough. This form is present in ksh93. * `${name/ }` -- you can use `$(printf '%s\n' "$name" | sed 's/foo/bar/')`, after changing shell patterns to regular expressions. This form is present in ksh93. * `${!name}` -- bash-specific; it is possible, but dangerous, to use `eval` to achieve similar effects; see [[BashFAQ/006]]. Note that using `$( )` has the side-effect of removing trailing newlines from the results. Furthermore, since many standard Posix utilities, such as `sed`, require text files as input, you should ensure their input ends in a newline. == Arrays == [[BashFAQ/005 | Arrays]] are not defined by POSIX (but are present in ksh); there is no easy general workaround for arrays. Here are some hints: * The positional parameters are a kind of array (only one array): {{{ #build a command dynamically see [[BashFAQ/050]] set -- 'mycommand' 'needs some complex' 'args' "$@" #access the i'th param set -- one two three i=2 eval var=\$$i #take care if i comes from some user input see below echo "$var" }}} * use `IFS` and `set -f` * `eval` is powerful but dangerous so use it wisely. See [[BashFAQ/048 | Eval command and security issues]]. == Conditionals == || || '''Works in bash''' || '''Change to for dash''' || '''Comment''' || || simple test || `[[` || use [ and use double quotes around the expansions `[ "$var" = "" ]` || [[ is not defined by POSIX, but is present in ksh || || pattern matching || `[[ foo = *glov ]]` || use `case` or `grep` || see [[BashFAQ/041]] || || equality with test || `==` || use `=` instead || only `=` is defined by POSIX, `=` works also in bash || || compare lexicographically. || `< >` || no change || present in dash and ksh, but not defined by POSIX. A possible workaround with awk: `awk -v v1="1" -v v2="fcd" 'BEGIN{exit !(v1 "" < "" v2)}'` || || compare modification times || `[[ file1 -nt file2 ]]` or `-ot` || `[ $(find 'file1' -prune -newer 'file2') ]` || `-prune` is required to avoid recursion; present in ksh || || check if 2 files are the same hardlink || `[[ file1 -ef file2 ]]` || ? || `-et` is not defined by POSIX, but is present in ksh || || `(( ))` || `(( ))` (without the `$`) acts like a command on its own || For simple comparison: `[ -lt ] (and -ne -gt -ge)` or `[ "$(( 3+1 < 5))" -eq 0 ]`. || present in ksh || || || || To assign a variable `var=$((3+1))` || || == Arithmetic == || || '''Works in bash''' || '''Change to for dash''' || '''Comment''' || || pre/pos increment/decrement || `++ --` || `i=$((i+1))` || - || || - || `let` || `: $((i=i+1))` || The `:` command can be used to peform side effects with an expansion || == Redirections == || || '''Works in bash''' || '''Change to for dash''' || '''Comment''' || || redirect both stdout and stderr || `>&` and `&>`|| `command > file 2>&1 or commnd 2>&1 | othercommand` || - || || || `|&` (bash4)|| `command 2>&1 | othercommand` || - || || duplicate and close|| `m>&n- m<&n-` || `m>&n n>&-` ||not defined by POSIX || || herestring|| `<<<"string"` || `echo | command`, or a here document to avoid a subshell (`<<EOF`)|| - || == Builtins == * `echo -n` or `-e` -- POSIX doesn't define any options, and furthermore allows `echo -e` to be the default behavior. Instead use `printf "%s\n"` (for normal echo) or `printf "%b\n"` (for `echo -e`); leave off the `\n` to simulate `echo -n`. * `printf -v` is not defined by POSIX. Also the `%q` format is not defined by POSIX. * `read` -- the only option defined by POSIX is `-r`; ksh has a different set of options that only partially overlaps with bash. * `shopt`, and therefore all the options it provides (`extglob`, `nullglob`, `dotglob`, etc.) are not defined by POSIX and are bash-specific * `local` -- there is no POSIX equivalent. You can use `$funcname_varname` to reduce the likelihood of conflicts, but even that is not enough for recursive functions. You can ensure that recursive calls occur in subshell environments (so there is a "local" copy of all variables), or pass all "local variables" as parameters (because the positional parameters `$@`, `$1`, `$2`, etc are truly local). dash explicitly supports `local` as a non-Posix extension; ksh uses `typeset` instead, which works like bash's `declare`. == Special Variables == || || '''Works in bash''' || '''Change to for dash''' || '''Comment''' || || keep track of the times|| `SECONDS` || `before=$(date +%s) ....seconds=$(( $(date +%s) - $before))` || `date +%s` is not POSIX; see [[BashFAQ/070|this faq for more info]]. Present in ksh|| || Generate a random number|| `RANDOM` || {{{random=$(awk 'BEGIN{srand(); printf "%d\n",(rand()*256)}'}}}) gives a number between 0 and 256 || Be sure to learn what `srand()` and `rand()` do, ie this method fails if you call `awk` several times rapidly. Instead generate all the numbers you need inside `awk`. Some systems also provide /dev/random and /dev/urandom. ksh has `RANDOM` || || Get the status of all the commands in a pipeline|| `PIPESTATUS` || Simplest solution {{{mkfifo fifo; command2 <fifo & command1 >fifo; echo $?}}} see NamedPipes || bash-specific; see [[ http://shell.cfajohnson.com/cus-faq-2.html#Q11 | this faq ]] and this script [[http://pipestatus.sourceforge.net/ | pipe status for POSIX shell]] || == More == * [[ http://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html#Bash-POSIX-Mode | The bash manual]] has a list of the differences between bash running in POSIX mode and a normal bash. Note that bash in POSIX mode is only guaranteed to run a shell written according to the POSIX specification. It ''doesn't'' mean that it will fail if you use bashisms in your scripts. * There is a handy perl script checkbashisms which is part of the debian devscripts package which can help point out bashisms in a particular script. ---- CategoryShell |
Hello! <<BR>> I'm Norwegian male :). <<BR>> I really like Games Club - Dungeons and Dragons, Monopoly, Etc.!<<BR>> <<BR>> Also visit my page ... [[http://www.free-vlc-download.com/|free vlc download]] |
Hello!
I'm Norwegian male :).
I really like Games Club - Dungeons and Dragons, Monopoly, Etc.!
Also visit my page ... free vlc download