# param-p.sh: test of parameter expansion for any POSIX-compliant shell posix="true" > file setup -d test_oE 'format for parameter expansion' a=a bracket -${a-\}}- -${a-'}'}- -${a-"}"}- -${a}}- bracket -${a-${a}}- -${a-$({ :;})}- bracket -${a-$(($({ :;})))}- -${a-${a-${a-${a}}}}- __IN__ [-a-][-a-][-a-][-a}-] [-a-][-a-] [-a-][-a-] __OUT__ test_oE -e 0 'simplest expansion' a=value unset b bracket -${a}- bracket -${b}- __IN__ [-value-] [--] __OUT__ test_oE 'expansion w/o braces, variables' aa=value _L0NG_variable_name=x unset aaa bracket -$aa- bracket -$aaa- bracket -$_L0NG_variable_name- __IN__ [-value-] [--] [-x-] __OUT__ test_oE 'expansion w/o braces, positional parameters' set a b bracket -$1- $22 __IN__ [-a-][b2] __OUT__ test_oE 'expansion w/o braces, special parameters' set 1 : dummy& zero="$0" dollar="$$" hyphen="$-" ex="$!" hash="$#" star="$*" at="$@" echoraw "$??" [ "$00" = "${zero}0" ] || echoraw '$0' [ "$00" = "${zero}0" ] [ "$$$$" = "$dollar$dollar" ] || echoraw '$$' [ "$$$$" = "$dollar$dollar" ] [ "$--" = "$hyphen-" ] || echoraw '$-' [ "$--" = "$hyphen-" ] [ "$!!" = "$ex!" ] || echoraw '$!' [ "$!!" = "$ex!" ] [ "$##" = "$hash#" ] || echoraw '$#' [ "$##" = "$hash#" ] [ "$**" = "$star*" ] || echoraw '$*' [ "$**" = "$star*" ] [ "$@@" = "$at@" ] || echoraw '$@' [ "$@@" = "$at@" ] __IN__ 0? __OUT__ test_oE 'double-quoted expansion is not subject to pathname expansion' a='*' bracket "${a}" bracket ${a+"${a}"} __IN__ [*] [*] __OUT__ test_oE 'double-quoted expansion is not subject to field splitting' a='a b c' bracket "${a}" bracket ${a+"${a}"} __IN__ [a b c] [a b c] __OUT__ test_oE 'tilde expansion in embedded word' HOME=/foo/bar b=b bracket ${a-~} ${a-~/} ${a-\~} bracket ${b+~} ${b+~/} ${b+\~} bracket ${c=~} ${d=~/} ${e=\~} (: ${a?~} ) 2>&1 | grep -Fq "$HOME" ; echo $? (: ${a?~/}) 2>&1 | grep -Fq "$HOME/"; echo $? (: ${a?\~}) 2>&1 | grep -Fq "~" ; echo $? __IN__ [/foo/bar][/foo/bar/][~] [/foo/bar][/foo/bar/][~] [/foo/bar][/foo/bar/][~] 0 0 0 __OUT__ test_oE 'parameter expansion in embedded word' b=b bracket ${a-x${b}x} ${a-\$b} bracket ${b+x${b}x} ${b+\$b} bracket ${c=x${b}x} ${d=\$b} (: ${a?x${b}x}) 2>&1 | grep -Fq "xbx"; echo $? (: ${a?\$b} ) 2>&1 | grep -Fq "$b" ; echo $? __IN__ [xbx][$b] [xbx][$b] [xbx][$b] 0 0 __OUT__ test_oE 'command substitution in embedded word' b=b bracket ${a-x$(echo -)x} bracket ${b+x$(echo -)x} bracket ${c=x$(echo -)x} (: ${a?x$(echo -)x}) 2>&1 | grep -Fq "x-x"; echo $? __IN__ [x-x] [x-x] [x-x] 0 __OUT__ test_oE 'arithmetic expansion in embedded word' b=b bracket ${a-x$((1+1))x} bracket ${b+x$((1+1))x} bracket ${c=x$((1+1))x} (: ${a?x$((1+1))x}) 2>&1 | grep -Fq "x2x"; echo $? __IN__ [x2x] [x2x] [x2x] 0 __OUT__ test_oE 'embedded word is expanded only if needed' a= unset b bracket -${a-${b?}}- -${b+${b?}}- -${a=${b?}}- -${a?${b?}}- a=a b= bracket -${a:-${b?}}- -${b:+${b?}}- -${a:=${b?}}- -${a:?${b?}}- __IN__ [--][--][--][--] [-a-][--][-a-][-a-] __OUT__ test_oE 'end of embedded word' a=a bracket ${a-x}b} ${a-x${a-x}x}b} __IN__ [ab}][ab}] __OUT__ ( setup 'a=a n=; unset u' test_oE '${a-b}' bracket "${a-x}" "${n-x}" "${u-x}" bracket "${a:-x}" "${n:-x}" "${u:-x}" __IN__ [a][][x] [a][x][x] __OUT__ test_oE '${a+b}' bracket "${a+x}" "${n+x}" "${u+x}" bracket "${a:+x}" "${n:+x}" "${u:+x}" __IN__ [x][x][] [x][][] __OUT__ test_oE '${a=b}' bracket "${a=x}" "${n=x}" "${u=x}" bracket "${a}" "${n}" "${u}" __IN__ [a][][x] [a][][x] __OUT__ test_oE '${a:=b}' bracket "${a:=x}" "${n:=x}" "${u:=x}" bracket "${a}" "${n}" "${u}" __IN__ [a][x][x] [a][x][x] __OUT__ test_O -d -e n 'assigning to read-only variable' readonly n bracket ${n:=} __IN__ test_O -d -e n 'assigning to positional parameter' bracket ${1:=} __IN__ test_O -d -e n 'assigning to special parameter' bracket ${*:=} __IN__ test_oE '${a?b}, success' bracket "${a?x}" "${n?x}" bracket "${a:?x}" __IN__ [a][] [a] __OUT__ test_O -d -e n '${unset?b}, failure w/o message' bracket "${u?}" __IN__ test_O -e n '${unset?b}, failure with message, exit status and stdout' bracket "${u?foo bar baz}" __IN__ test_OE -e 0 '${unset?b}, failure with message, stderr' (: "${u?foo bar baz}") 2>&1 | grep -Fq 'foo bar baz' __IN__ test_O -d -e n '${null?b}, failure' bracket "${n:?}" __IN__ test_O -d -e n '${unset?b}, failure' bracket "${u:?}" __IN__ ) test_oE 'length of valid variables' zero= one=a two=bb five=ccccc twenty=dddddddddddddddddddd bracket ${#zero} ${#one} ${#five} ${#twenty} set '' a bb cccc bracket ${#1} ${#2} ${#3} ${#4} : dummy& zero="$0" dollar="$$" hyphen="$-" ex="$!" hash="$#" echoraw '${#?}' ${#?} [ "${#0}" = "${#zero}" ] || echoraw '$0' [ "${#0}" = "${#zero}" ] [ "${#$}" = "${#dollar}" ] || echoraw '$$' [ "${#$}" = "${#dollar}" ] [ "${#-}" = "${#hyphen}" ] || echoraw '$-' [ "${#-}" = "${#hyphen}" ] [ "${#!}" = "${#ex}" ] || echoraw '$!' [ "${#!}" = "${#ex}" ] # ambiguous... # [ "${##}" = "${#hash}" ] || echoraw '$#' [ "${##}" = "${#hash}" ] __IN__ [0][1][5][20] [0][1][2][4] ${#?} 1 __OUT__ test_oE -e 0 'length of unset variables, success' unset u echoraw ${#u} __IN__ 0 __OUT__ test_O -d -e n 'length of unset variables, failure' -u unset u echoraw ${#u} __IN__ test_oE 'disambiguation of ${#...' bracket ${#-""} bracket ${#?X} bracket ${#+""} "${#:+}" bracket ${#=""} "${#:=}" __IN__ [0] [0] [][] [0][0] __OUT__ test_oE 'removing shortest matching prefix' a=1-2-3-4 s='***' h='###' bracket "${a#1}" "${a#*1}" "${a#1*}" "${a#1*-}" bracket "${a#*-}" "${a#*}" "${a#-*}" "${a#*-*}" bracket "${a#2}" "${s#'*'}" "${h#'#'}" __IN__ [-2-3-4][-2-3-4][-2-3-4][2-3-4] [2-3-4][1-2-3-4][1-2-3-4][2-3-4] [1-2-3-4][**][##] __OUT__ test_oE 'removing longest matching prefix' a=1-2-3-4 s='***' h='###' bracket "${a##1}" "${a##*1}" "${a##1*}" "${a##1*-}" bracket "${a##*-}" "${a##*}" "${a##-*}" "${a##*-*}" bracket "${a##2}" "${s##'*'}" "${h###}" __IN__ [-2-3-4][-2-3-4][][4] [4][][1-2-3-4][] [1-2-3-4][**][##] __OUT__ test_oE 'removing shortest matching suffix' a=1-2-3-4 s='***' p='%%%' bracket "${a%4}" "${a%*4}" "${a%4*}" "${a%-*4}" bracket "${a%*-}" "${a%*}" "${a%-*}" "${a%*-*}" bracket "${a%3}" "${s%'*'}" "${p%'%'}" __IN__ [1-2-3-][1-2-3-][1-2-3-][1-2-3] [1-2-3-4][1-2-3-4][1-2-3][1-2-3] [1-2-3-4][**][%%] __OUT__ test_oE 'removing longest matching suffix' a=1-2-3-4 s='***' p='%%%' bracket "${a%%4}" "${a%%*4}" "${a%%4*}" "${a%%-*4}" bracket "${a%%*-}" "${a%%*}" "${a%%-*}" "${a%%*-*}" bracket "${a%%3}" "${s%%'*'}" "${p%%%}" __IN__ [1-2-3-][][1-2-3-][1] [1-2-3-4][][1][] [1-2-3-4][**][%%] __OUT__ test_oE 'tilde expansion in embedded pattern' HOME=/home/foo a=/home/foo/bar b=/usr/home/foo bracket ${a#~} "${a#~}" ${a#"~"} bracket ${a##~} "${a##~}" ${a##"~"} bracket ${b%~} "${b%~}" ${b%"~"} bracket ${b%%~} "${b%%~}" ${b%%"~"} __IN__ [/bar][/bar][/home/foo/bar] [/bar][/bar][/home/foo/bar] [/usr][/usr][/usr/home/foo] [/usr][/usr][/usr/home/foo] __OUT__ test_oE 'parameter expansion in embedded pattern' w='ab\bc' a='*' b='\' bracket ${w#${a}b} "${w#${a}b}" ${w#"${a}b"} bracket ${w##${a}b} "${w##${a}b}" ${w##"${a}b"} bracket ${w%b${a}} "${w%b${a}}" ${w%"b${a}"} bracket ${w%%b${a}} "${w%%b${a}}" ${w%%"b${a}"} # XCU 2.9.4 implies unquoted backslashes are special in the pattern. bracket ${w#*${b}b} "${w#*${b}b}" ${w#"*${b}b"} bracket ${w##*${b}b} "${w##*${b}b}" ${w##"*${b}b"} bracket ${w%${b}b*} "${w%${b}b*}" ${w%"${b}b*"} bracket ${w%%${b}b*} "${w%%${b}b*}" ${w%%"${b}b*"} __IN__ [\bc][\bc][ab\bc] [c][c][ab\bc] [ab\][ab\][ab\bc] [a][a][ab\bc] [\bc][\bc][ab\bc] [c][c][ab\bc] [ab\][ab\][ab\bc] [a][a][ab\bc] __OUT__ test_oE 'command substitution in embedded pattern' w='ab\bc' bracket ${w#$(echo '*')b} "${w#$(echo '*')b}" ${w#"$(echo '*')b"} bracket ${w##$(echo '*')b} "${w##$(echo '*')b}" ${w##"$(echo '*')b"} bracket ${w%b$(echo '*')} "${w%b$(echo '*')}" ${w%"b$(echo '*')"} bracket ${w%%b$(echo '*')} "${w%%b$(echo '*')}" ${w%%"b$(echo '*')"} __IN__ [\bc][\bc][ab\bc] [c][c][ab\bc] [ab\][ab\][ab\bc] [a][a][ab\bc] __OUT__ test_oE 'arithmetic expansion in embedded pattern' w='12223' bracket ${w#*$((1+1))} "${w#*$((1+1))}" ${w#"*$((1+1))"} bracket ${w##*$((1+1))} "${w##*$((1+1))}" ${w##"*$((1+1))"} bracket ${w%$((1+1))*} "${w%$((1+1))*}" ${w%"$((1+1))*"} bracket ${w%%$((1+1))*} "${w%%$((1+1))*}" ${w%%"$((1+1))*"} __IN__ [223][223][12223] [3][3][12223] [122][122][12223] [1][1][12223] __OUT__ ### Examples from informative sections of POSIX test_oE 'effects of omitting braces' a=1 set 2 echo ${a}b-$ab-${1}0-${10}-$10 __IN__ 1b--20--20 __OUT__ test_oE 'testing existence of positional parameter' set a b c echo ${3:+posix} echo ${4-posix} __IN__ posix posix __OUT__ test_oE 'removing prefix with expanded word' HOME=/home/foo x=$HOME/src/cmd echo ${x#$HOME} __IN__ /src/cmd __OUT__ test_oE 'special parameter #' echo $# set x echo $# set x 'y y' z echo $# set a b c d e f g h i j k echo $# __IN__ 0 1 3 11 __OUT__ test_oE 'special parameter ?' true echo $? (exit 1) echo $? (exit 123) echo $? __IN__ 0 1 123 __OUT__ test_OE -e 0 'special parameter -' -eu set +C v=$- [ "$(echo $v | grep e | grep u | grep -v C)" ] __IN__ test_OE 'special parameter $' [ $$ -eq "$(echo $$)" ] || echo [ $$ -eq "$(echo $$)" ] kill $$ echo not reached __IN__ # POSIX requires $! to expand to the process ID of the last command in the # pipeline. To meet the requirement, the shell needs to short-circuit the # creation of the subshell for the last pipeline component. : TODO not yet fully implemented <<\__OUT__ test_oE 'special parameter !' mkfifo fifo echo foo | { trap 'echo trapped; exit 0' USR1 cat cat fifo }& exec 3>fifo echo bar >&3 kill -s USR1 $! # should kill the last process of the background pipeline exec 3>&- wait $! __IN__ foo bar trapped __OUT__ # Special parameter 0 is tested in sh-p.tst #test_oE 'special parameter 0' test_oE 'special parameter *, quoted, unset IFS' unset IFS bracket "$*" set a bracket "$*" set a 'b b' cc bracket "$*" set '' bracket "$*" set '' '' bracket "$*" set ' a ' ' b ' ' cc ' bracket "$*" __IN__ [] [a] [a b b cc] [] [ ] [ a b cc ] __OUT__ test_oE 'special parameter *, quoted, non-default IFS' IFS=xyz bracket "$*" set a bracket "$*" set a 'b b' cc bracket "$*" set '' bracket "$*" set '' '' bracket "$*" set ' a ' ' b ' ' cc ' bracket "$*" __IN__ [] [a] [axb bxcc] [] [x] [ a x b x cc ] __OUT__ test_oE 'special parameter *, quoted, empty IFS' IFS= bracket "$*" set a bracket "$*" set a 'b b' cc bracket "$*" set '' bracket "$*" set '' '' bracket "$*" set ' a ' ' b ' ' cc ' bracket "$*" __IN__ [] [a] [ab bcc] [] [] [ a b cc ] __OUT__ test_oE 'special parameter *, unquoted' bracket $* bracket ""$* bracket $*"" set a bracket $* bracket ""$* bracket $*"" set a 'b b' cc bracket $* bracket ""$* bracket $*"" IFS= bracket $* bracket ""$* bracket $*"" __IN__ [] [] [a] [a] [a] [a][b][b][cc] [a][b][b][cc] [a][b][b][cc] [a][b b][cc] [a][b b][cc] [a][b b][cc] __OUT__ test_oE 'special parameter @, quoted' bracket "$@" bracket "$@""$@" - "$@""$@""$@" bracket "=$@=" null= bracket "$null""$@" bracket "$@""$null" bracket "$null""$@""$null" - "$null""$null""$@" - "$@""$null""$null" bracket "$null""$@$null" - "$null""$null$@" - \ "$@$null""$null" - "$null$@""$null" set a bracket "$@" bracket "=$@=" set a 'b b' cc bracket "$@" bracket "=$@=" bracket "$@$@" set '' bracket "$@" bracket "=$@=" bracket "$@$@" - "$null""$@" - "$@""$null" - "$null""$@""$null" set '' '' bracket "$@" bracket "=$@=" bracket "$@$@" bracket "$null""$@""$null" set ' a ' ' b ' ' cc ' bracket "$@" __IN__ [-] [==] [] [] [][-][][-][] [][-][][-][][-][] [a] [=a=] [a][b b][cc] [=a][b b][cc=] [a][b b][cca][b b][cc] [] [==] [][-][][-][][-][] [][] [=][=] [][][] [][] [ a ][ b ][ cc ] __OUT__ # Expansion of unquoted $@ is the same as that of unquoted $* test_oE 'special parameter @, unquoted' bracket $@ bracket ""$@ bracket $@"" set a bracket $@ bracket ""$@ bracket $@"" set a 'b b' cc bracket $@ bracket ""$@ bracket $@"" IFS= bracket $@ bracket ""$@ bracket $@"" __IN__ [] [] [a] [a] [a] [a][b][b][cc] [a][b][b][cc] [a][b][b][cc] [a][b b][cc] [a][b b][cc] [a][b b][cc] __OUT__ test_oE '${1+"$@"}' bracket ${1+"$@"} set a bracket ${1+"$@"} set a 'b b' cc bracket ${1+"$@"} set '' bracket ${1+"$@"} set '' '' bracket ${1+"$@"} set '' '' '' bracket ${1+"$@"} set ' ' ' ' ' ' bracket ${1+"$@"} __IN__ [a] [a][b b][cc] [] [][] [][][] [ ][ ][ ] __OUT__ test_oE '${foo:-"$@"}' set a 'b b' cc unset foo bracket ${foo:-"$@"} foo= bracket ${foo:-"$@"} foo=bar bracket ${foo:-"$@"} __IN__ [a][b b][cc] [a][b b][cc] [bar] __OUT__