《Shell中的替換規則》
${parameter}與$parameter相同,代表引數parameter的值。在某些特定環境下,只有不太模糊或者說是精確的的${parameter}形式有效。
可用於將變數與字串連線
your_id=${USER}-on-${HOSTNAME}echo "${your_id}" # cory-on-cory-server# Old $PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/binecho "Old \$PATH = $PATH" PATH=${PATH}:/opt/bin# New $PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/opt/binecho "New \$PATH = $PATH"
${parameter-default},${parameter:-default}如果parameter未設定,則使用default預設值
var1=1var2=2echo ${var1-$var2} # 1echo ${var3-$var2} # 2# 如果變數${username}未設定,則輸出命令`whoami`的值echo ${username-`whoami`} # cory
要注意${parameter-default}和${parameter:-default}幾乎相等。 多出的冒號 ':'僅在引數已宣告但為null時才起作用。
#!/bin/bash# param-sub.sh# Whether a variable has been declared#+ affects triggering of the default option#+ even if the variable is null.# 變數是否宣告影響預設值的觸發,即使變數為空username0=echo "username0 has been decalare, but is set to null."echo "username0 = ${username0-`whoami`}"# Will not echo.# 不會輸出echoecho username1 has not been declared.echo "username1 = ${username1-`whoami`}"# Will echo.# 會輸出username2=echo "username2 has been declared, but is set to null."echo "username2 = ${username2:-`whoami`}"# ^# Will echo because of :- rather than just - in condition test.# Compare to first instance, above.# 會輸出,因為有一個冒號## Once again:variable=# variable has been declared, but is set to null.echo "${variable-0}" # (no output)echo "${variable:-1}" # 1# ^unset variableecho "${variable-2}" # 2echo "${variable:-3}" # 3exit 0
結果輸出:
username0 has been decalare, but is set to null.username0 =username1 has not been declared.username1 = coryusername2 has been declared, but is set to null.username2 = cory123
預設引數構造可用於在指令碼中提供“缺少的”命令列引數。
#!/bin/bash# default.sh# 如果執行指令碼沒有傳入引數,則使用預設值param=${1:-"default_param"}echo "${param}"
結果輸出:
${parameter=default},${parameter:=default}如果未設定引數,請將其設定為預設值。兩種形式幾乎相等。 僅當$parameter已宣告且為null時,冒號':'才有所不同,與${parameter:-default}用法一致
echo ${var=abc} # abc# 因為var已經被強制設定預設值,所以輸出為定義值echo ${var=xyz} # abc
${parameter+alt_value}, ${parameter:+alt_value}
如果設定引數,使用alt_value值,否則使用空值。
兩種形式幾乎相等。 僅當$parameter已宣告且為null時,冒號':'才有所不同,檢視如下例子
#!/bin/bashecho "###### \${parameter+alt_value} ########"echoa=${param1+cory}echo "a = $a" # a =param2=a=${param2+cory}echo "a = $a" # a = coryparam3=123a=${param3+cory}echo "a = $a" # a = coryechoecho "###### \${parameter:+alt_value} ########"echoa=${param4:+cory}echo "a = $a" # a =param5=a=${param5:+cory}echo "a = $a" # a =# Different result from a=${param5+cory}param6=123a=${param6:+cory}echo "a = $a" # a = cory
結果:
###### ${parameter+alt_value} ########a =a = corya = cory###### ${parameter:+alt_value} ########a =a =a = cory
${parameter?err_msg}, ${parameter:?err_msg}如果設定引數,使用引數值,否則列印輸出err_msg資訊,並且狀態1退出指令碼
兩種形式幾乎相等。 僅當$parameter已宣告且為null時,冒號':'才有所不同,與${parameter+alt_value}使用方法類似
#!/bin/bash# 校驗系統環境變數# 預防性維護# 例如:如果$USER,控制檯上的使用者,未設定,機器將無法識別: ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?} echo echo "Name of the machine is $HOSTNAME." echo "You are $USER." echo "Your home directory is $HOME." echo "Your mail INBOX is located in $MAIL." echo echo "If you are reading this message," echo "critical environmental variables have been set." echo echo# ------------------------------------------------------# The ${variablename?} construction can also check#+ for variables set within the script.ThisVariable=Value-of-ThisVariable# Note, by the way, that string variables may be set#+ to characters disallowed in their names.: ${ThisVariable?}echo "Value of ThisVariable is $ThisVariable".echo; echo: ${ZZXy23AB?"ZZXy23AB has not been set."}# Since ZZXy23AB has not been set,#+ then the script terminates with an error message.# You can specify the error message.# : ${variablename?"ERROR MESSAGE"}# Same result with: dummy_variable=${ZZXy23AB?}# dummy_variable=${ZZXy23AB?"ZXy23AB has not been set."}## echo ${ZZXy23AB?} >/dev/null# Compare these methods of checking whether a variable has been set#+ with "set -u" . . .echo "You will not see this message, because script already terminated."HERE=0exit $HERE # Will NOT exit here.# In fact, this script will return an exit status (echo $?) of 1.
結果:
Name of the machine is cory-server.You are cory.Your home directory is /home/cory.Your mail INBOX is located in /var/mail/cory.If you are reading this message,critical environmental variables have been set.Value of ThisVariable is Value-of-ThisVariable../err_msg.sh: line 34: ZZXy23AB: ZZXy23AB has not been set.
這裡們需要了解冒號(:)是內嵌命令,官方給的解釋:
: [arguments]
No effect; the command does nothing beyond expanding arguments and performing any specified redirections. The return status is zero.
也就是冒號命令本身沒有實際效果,該命令除了擴充套件引數和執行任何指定的重定向外,什麼也不 做。 返回狀態為零。
但是與當前的${parameter?}結合進行引數校驗
${#var}字串長度($var中的字元數)。對於陣列,$ {#array}是陣列中第一個元素的長度。
例外情況:
$ {#*}和$ {#@}給出位置引數的數量。
對於陣列,$ {#array [*]}和$ {#array [@]}給出陣列中元素的數量。
#!/bin/bash# length.shE_NO_ARGS=65if [ $# -eq 0 ] # Must have command-line args to demo script.then echo "Please invoke this script with one or more command-line arguments." exit $E_NO_ARGSfivar01=abcdEFGH28ijecho "var01 = ${var01}"echo "Length of var01 = ${#var01}"# Now, let's try embedding a space.var02="abcd EFGH28ij"echo "var02 = ${var02}"echo "Length of var02 = ${#var02}"echo "Number of command-line arguments passed to script = ${#@}"echo "Number of command-line arguments passed to script = ${#*}"exit 0
結果:
pwd # /home/coryecho `basename $PWD` # coryecho "${PWD##*/}" # coryfilename=test.dataecho "${filename##*.}" # data
${var%Pattern},${var%%Pattern}
${var%Pattern}從$var中刪除與$var後端匹配的$Pattern最短部分。
#!/bin/bash# Pattern matching using the # ## % %% parameter substitution operators.var1=abcd12345abc6789pattern1=a*c # * (wild card) matches everything between a - c.echoecho "var1 = $var1" # abcd12345abc6789echo "var1 = ${var1}" # abcd12345abc6789 # (alternate form)echo "Number of characters in ${var1} = ${#var1}"echoecho "pattern1 = $pattern1" # a*c (everything between 'a' and 'c')echo "--------------"echo '${var1#$pattern1} =' "${var1#$pattern1}" # d12345abc6789# Shortest possible match, strips out first 3 characters abcd12345abc6789# ^^^^^ |-|echo '${var1##$pattern1} =' "${var1##$pattern1}" # 6789# Longest possible match, strips out first 12 characters abcd12345abc6789# ^^^^^ |----------|echo; echo; echopattern2=b*9 # everything between 'b' and '9'echo "var1 = $var1" # Still abcd12345abc6789echoecho "pattern2 = $pattern2"echo "--------------"echo '${var1%pattern2} =' "${var1%$pattern2}" # abcd12345a# Shortest possible match, strips out last 6 characters abcd12345abc6789# ^^^^ |----|echo '${var1%%pattern2} =' "${var1%%$pattern2}" # a# Longest possible match, strips out last 12 characters abcd12345abc6789# ^^^^ |-------------|# Remember, # and ## work from the left end (beginning) of string,# % and %% work from the right end.echoexit 0
結果:
var1 = abcd12345abc6789var1 = abcd12345abc6789Number of characters in abcd12345abc6789 = 16pattern1 = a*c--------------${var1#$pattern1} = d12345abc6789${var1##$pattern1} = 6789var1 = abcd12345abc6789pattern2 = b*9--------------${var1%pattern2} = abcd12345a${var1%%pattern2} = a
另外一個例子:
更改字尾名
#!/bin/bash# rfe.sh: Renaming file extensions.## rfe old_extension new_extension## Example:# To rename all *.gif files in working directory to *.jpg,# rfe gif jpgE_BADARGS=65case $# in 0|1) # The vertical bar means "or" in this context. echo "Usage: `basename $0` old_file_suffix new_file_suffix" exit $E_BADARGS # If 0 or 1 arg, then bail out. ;;esacfor filename in *.$1# Traverse list of files ending with 1st argument.do mv $filename ${filename%$1}$2 # Strip off part of filename matching 1st argument, #+ then append 2nd argument.doneexit 0
${var:pos}變數var從偏移量pos開始擴充套件。
me=coryecho ${me:2} # ry
${var:pos:len}
從偏移pos擴充套件到最多len個變數var的字元。
me=coryecho ${me:1:2} # or
${var/Patter/Replacement}
Pattern的第一個匹配項,在var中用Replacement替換。
sen="I am god" echo ${sen/god/cory} # I am cory
${var//Pattern//Replacement}
全域性替換。var中所有Pattern的匹配項都用Replacement替換。
#!/bin/bashvar1=abcd-1234-defgecho "var1 = $var1"t=${var1#*-*}echo "var1 (with everything, up to and including first - stripped out) = $t"# t=${var1#*-} works just the same,#+ since # matches the shortest string,#+ and * matches everything preceding, including an empty string.# 匹配最短字串 空字串也包含t=${var1##*-*}echo "If var1 contains a \"-\", returns empty string... var1 = $t"t=${var1%*-*}echo "var1 (with everything from the last - on stripped out) = $t"echo# -------------------------------------------path_name=/home/bozo/ideas/thoughts.for.today# -------------------------------------------echo "path_name = $path_name"t=${path_name##/*/}echo "path_name, stripped of prefixes = $t"# Same effect as t=`basename $path_name` in this particular case.# t=${path_name%/}; t=${t##*/} is a more general solution,#+ but still fails sometimes.# If $path_name ends with a newline, then `basename $path_name` will not work,#+ but the above expression will.# 如果變數包含新行newline,使用函式basename就會有問題,而使用上邊方法則沒有問題t=${path_name%/*.*}# Same effect as t=`dirname $path_name`echo "path_name, stripped of suffixes = $t"# These will fail in some cases, such as "../", "/foo////", # "foo/", "/".# Removing suffixes, especially when the basename has no suffix,#+ but the dirname does, also complicates matters.echot=${path_name:11}echo "$path_name, with first 11 chars stripped off = $t"t=${path_name:11:5}echo "$path_name, with first 11 chars stripped off, length 5 = $t"echot=${path_name/bozo/clown}echo "$path_name with \"bozo\" replaced by \"clown\" = $t"t=${path_name/today/}echo "$path_name with \"today\" deleted = $t"t=${path_name//o/O}echo "$path_name with all o's capitalized = $t"t=${path_name//o/}echo "$path_name with all o's deleted = $t"exit 0
結果:
var1 = abcd-1234-defgvar1 (with everything, up to and including first - stripped out) = 1234-defgIf var1 contains a "-", returns empty string... var1 =var1 (with everything from the last - on stripped out) = abcd-1234path_name = /home/bozo/ideas/thoughts.for.todaypath_name, stripped of prefixes = thoughts.for.todaypath_name, stripped of suffixes = /home/bozo/ideas/home/bozo/ideas/thoughts.for.today, with first 11 chars stripped off = ideas/thoughts.for.today/home/bozo/ideas/thoughts.for.today, with first 11 chars stripped off, length 5 = ideas/home/bozo/ideas/thoughts.for.today with "bozo" replaced by "clown" = /home/clown/ideas/thoughts.for.today/home/bozo/ideas/thoughts.for.today with "today" deleted = /home/bozo/ideas/thoughts.for./home/bozo/ideas/thoughts.for.today with all o's capitalized = /hOme/bOzO/ideas/thOughts.fOr.tOday/home/bozo/ideas/thoughts.for.today with all o's deleted = /hme/bz/ideas/thughts.fr.tday
${var/#Pattern/Replacement}如果var的字首與Pattern匹配,則將Replacement替換為Pattern。
echo ${me} # coryecho ${me/#c/g} # gory
${var/%Pattern/Replacement}
如果var的字尾與Pattern匹配,則將Replacement替換為Pattern。
#!/bin/bash# var-match.sh:# Demo of pattern replacement at prefix / suffix of string.v0=abc1234zip1234abc # Original variable.echo "v0 = $v0" # abc1234zip1234abcecho# Match at prefix (beginning) of string.v1=${v0/#abc/ABCDEF} # abc1234zip1234abc # |-|echo "v1 = $v1" # ABCDEF1234zip1234abc # |----|# Match at suffix (end) of string.v2=${v0/%abc/ABCDEF} # abc1234zip123abc # |-|echo "v2 = $v2" # abc1234zip1234ABCDEF # |----|echo# ----------------------------------------------------# Must match at beginning / end of string,#+ otherwise no replacement results.# ----------------------------------------------------v3=${v0/#123/000} # Matches, but not at beginning.echo "v3 = $v3" # abc1234zip1234abc# NO REPLACEMENT.v4=${v0/%123/000} # Matches, but not at end.echo "v4 = $v4" # abc1234zip1234abc# NO REPLACEMENT.exit 0
結果:
v0 = abc1234zip1234abcv1 = ABCDEF1234zip1234abcv2 = abc1234zip1234ABCDEFv3 = abc1234zip1234abcv4 = abc1234zip1234abc
${!varprefix*},${!varprefix@}
匹配所有以varprefix開頭的先前宣告的變數的名稱。間接引用帶有感嘆號(!)
# 這是間接引用的變體,只是帶了個*或者@.# Bash, version 2.04, adds this feature.xyz23=whateverxyz24=a=${!xyz*} # Expands to *names* of declared variables# ^ ^ ^ + beginning with "xyz".echo "a = $a" # a = xyz23 xyz24a=${!xyz@} # Same as above.echo "a = $a" # a = xyz23 xyz24echo "---"abc23=something_elseb=${!abc*}echo "b = $b" # b = abc23c=${!b} # 常見的間接引用echo $c # something_else