shell高级变量操作

一、内置变量

1.$BASH

Bash的二进制程序文件的路径(脚本解释器的路径)

$ vim test.sh

输入代码:

 
  1. #!/bin/bash

  2. echo $BASH

运行代码:

$ bash test.sh

2.$FUNCNAME

当前函数的名字

$ vim test.sh

输入代码:

 
  1. #!/bin/bash

  2. xyz23 ()

  3. {

  4. echo "$FUNCNAME now executing."

  5. # 正常情况下打印: xyz23 now executing.

  6. # 在个别版本的bash中,并不支持$FUNCNAME内置变量

  7. }

  8.  
  9. xyz23

  10.  
  11. echo "FUNCNAME = $FUNCNAME" # FUNCNAME =

  12. # 超出函数的作用域就变为null值了.

运行代码:

$ bash test.sh

3.$IFS

内部域分隔符,这个变量用来决定 Bash 在解释字符串时如何识别域,或者单词边界。

$IFS默认为空白(空格,制表符,和换行符),但这是可以修改的,比如,在分析逗号分

隔的数据文件时,就可以设置为逗号,注意 $* 使用的是保存在$IFS中的第一个字符。

$ vim test.sh

输入代码:

 
  1. #!/bin/bash

  2. # $IFS 处理空白与处理其他字符不同.

  3.  
  4. output_args_one_per_line()

  5. {

  6. for arg

  7. do echo "[$arg]"

  8. done

  9. }

  10.  
  11. echo; echo "IFS=\" \""

  12. echo "-------"

  13.  
  14. IFS=" "

  15. var=" a b c "

  16. output_args_one_per_line $var # output_args_one_per_line `echo " a b c "`

  17. #

  18. # [a]

  19. # [b]

  20. # [c]

  21.  
  22.  
  23. echo; echo "IFS=:"

  24. echo "-----"

  25.  
  26. IFS=:

  27. var=":a::b:c:::" # 与上边一样, 但是用" "替换了":".

  28. output_args_one_per_line $var

  29. #

  30. # []

  31. # [a]

  32. # []

  33. # [b]

  34. # [c]

  35. # []

  36. # []

  37. # []

  38.  
  39. # 同样的事情也会发生在awk的"FS"域中.

  40.  
  41. # 感谢, Stephane Chazelas.

  42.  
  43. echo

  44.  
  45. exit 0

注意: 你可能对上面的for循环和变量arg有疑问,这将在下一节进行讨论。

运行代码:

$ bash test.sh

4、$REPLY

当没有参数变量提供给 read 命令的时候,这个变量会作为默认变量提供给 read 命令。也

可以用于 select 菜单,但是只提供所选择变量的编号,而不是变量本身的值。在个别版本的bash中,并不支持内置变量$REPLY。

$ vim test.sh

输入代码:

 
  1. #!/bin/bash

  2. # reply.sh

  3.  
  4. # REPLY是提供给'read'命令的默认变量.

  5.  
  6. echo

  7. echo -n "What is your favorite vegetable? "

  8. read

  9.  
  10. echo "Your favorite vegetable is $REPLY."

  11. # 当且仅当没有变量提供给"read"命令时,

  12. #+ REPLY才保存最后一个"read"命令读入的值.

  13.  
  14. echo

  15. echo -n "What is your favorite fruit? "

  16. read fruit

  17. echo "Your favorite fruit is $fruit."

  18. echo "but..."

  19. echo "Value of \$REPLY is still $REPLY."

  20. # $REPLY还是保存着上一个read命令的值,

  21. #+ 因为变量$fruit被传入到了这个新的"read"命令中.

  22.  
  23. echo

  24.  
  25. exit 0

运行代码:

$ bash test.sh

5.通过$*$@列出所有的参数

"$*" 所有的位置参数都被看作为一个单词。

$@与 $* 相同,但是每个参数都是一个独立的引用字符串,这就意味着,参数是被完整

传递的,并没有被解释或扩展。这也意味着,参数列表中每个参数都被看作为单独的单词。

$ vim test.sh

输入代码:

 
  1. #!/bin/bash

  2. # 多使用几个参数来调用这个脚本, 比如"one two three".

  3.  
  4. E_BADARGS=65

  5.  
  6. if [ ! -n "$1" ]

  7. then

  8. echo "Usage: `basename $0` argument1 argument2 etc."

  9. exit $E_BADARGS

  10. fi

  11.  
  12. echo

  13.  
  14. index=1 # 起始计数.

  15.  
  16. echo "Listing args with \"\$*\":"

  17. for arg in "$*" # 如果"$*"不被""(双引号)引用,那么将不能正常地工作.

  18. do

  19. echo "Arg #$index = $arg"

  20. let "index+=1"

  21. done # $* 将所有的参数看成一个单词.

  22. echo "Entire arg list seen as single word."

  23.  
  24. echo

  25.  
  26. index=1 # 重置计数(译者注: 从1开始).

  27.  
  28. echo "Listing args with \"\$@\":"

  29. for arg in "$@"

  30. do

  31. echo "Arg #$index = $arg"

  32. let "index+=1"

  33. done # $@ 把每个参数都看成是单独的单词.

  34. echo "Arg list seen as separate words."

  35.  
  36. echo

  37.  
  38. index=1 # 重置计数(译者注: 从1开始).

  39.  
  40. echo "Listing args with \$* (unquoted):"

  41. for arg in $*

  42. do

  43. echo "Arg #$index = $arg"

  44. let "index+=1"

  45. done # 未引用的$*将会把参数看成单独的单词.

  46. echo "Arg list seen as separate words."

  47.  
  48. exit 0

运行代码:

$ bash test.sh

二、操作字符串

1.字符串长度

$ vim test.sh

输入代码:

 
  1. #!/bin/bash

  2.  
  3. stringZ=abcABC123ABCabc

  4.  
  5. echo ${#stringZ} # 15

  6. expr length $stringZ # 15

运行代码:

$ bash test.sh

2.使用awk来处理字符串

Bash脚本也可以调用awk的字符串操作功能来代替它自己内建的字符串操作。

例子:提取字符串

$ vim test.sh

输入代码:

 
  1. #!/bin/bash

  2.  
  3. String=23skidoo1

  4. # 012345678 Bash

  5. # 123456789 awk

  6. # 注意不同的字符串索引系统:

  7. # Bash的第一个字符是从'0'开始记录的.

  8. # Awk的第一个字符是从'1'开始记录的.

  9.  
  10. echo ${String:2:4} # 位置 3 (0-1-2), 4 个字符长

  11. # skid

  12.  
  13. # awk中等价于${string:pos:length}的命令是substr(string,pos,length).

  14. echo | awk '

  15. {

  16. print substr("'"${String}"'",3,4) # skid

  17. }

  18. '

  19. # 使用一个空的"echo"通过管道传递给awk一个假的输入,

  20. #+ 这样就不必提供一个文件名给awk.

  21.  
  22. exit 0

运行代码:

$ bash test.sh

三、参数替换

1.处理和(或)扩展变量

${parameter} 与 $parameter 相同,也就是变量 parameter 的值。但在某些情况下,最好使用${parameter} 以避免产生混淆。

 
  1. your_id=${USER}-on-${HOSTNAME}

  2. echo "$your_id"

  3. echo "Old \$PATH = $PATH"

  4. PATH=${PATH}:/opt/bin #在脚本的生命周期中, /opt/bin会被添加到$PATH变量中.

  5. echo "New \$PATH = $PATH"

${parameter-default} 如果变量 parameter 没被声明,那么就使用默认值。

${parameter:-default} 如果变量 parameter 没被设置,那么就使用默认值。

 
  1. #!/bin/bash

  2. # param-sub.sh

  3.  
  4. # 一个变量是否被声明或设置,

  5. #+ 将会影响这个变量是否使用默认值,

  6. #+ 即使这个变量值为空(null).

  7.  
  8. username0=

  9. echo "username0 has been declared, but is set to null."

  10. echo "username0 = ${username0-`whoami`}"

  11. # 不会有输出.

  12.  
  13. echo

  14.  
  15. echo username1 has not been declared.

  16. echo "username1 = ${username1-`whoami`}"

  17. # 将会输出默认值.

  18.  
  19. username2=

  20. echo "username2 has been declared, but is set to null."

  21. echo "username2 = ${username2:-`whoami`}"

  22. # ^

  23. # 会输出, 因为:-会比-多一个条件测试.

  24. # 可以与上边的例子比较一下.

指定方式 说明
${parameter-default} 如果变量 parameter 没被声明,那么就使用默认值。
${parameter:-default} 如果变量 parameter 没被设置,那么就使用默认值。
${parameter=default} 如果变量parameter没声明,那么就把它的值设为default。
${parameter:=default} 如果变量parameter没设置,那么就把它的值设为default。
${parameter+alt_value} 如果变量parameter被声明了,那么就使用alt_value,否则就使用null字符串。
${parameter:+alt_value} 如果变量parameter被设置了,那么就使用alt_value,否则就使用null字符串。
${parameter?err_msg} 如果parameter已经被声明,那么就使用设置的值,否则打印err_msg错误消息。
${parameter:?err_msg} 如果parameter已经被设置,那么就使用设置的值,否则打印err_msg错误消息。
 
  1. #!/bin/bash

  2.  
  3. # 检查一些系统环境变量.

  4. # 这是一种可以做一些预防性保护措施的好习惯.

  5. # 比如, 如果$USER(用户在控制台上中的名字)没有被设置的话,

  6. #+ 那么系统就会不认你.

  7.  
  8. : ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?}

  9. echo

  10. echo "Name of the machine is $HOSTNAME."

  11. echo "You are $USER."

  12. echo "Your home directory is $HOME."

  13. echo "Your mail INBOX is located in $MAIL."

  14. echo

  15. echo "If you are reading this message,"

  16. echo "critical environmental variables have been set."

  17. echo

  18. echo

  19.  
  20. # ------------------------------------------------------

  21.  
  22. # ${variablename?}结构

  23. #+ 也能够检查脚本中变量的设置情况.

  24.  
  25. ThisVariable=Value-of-ThisVariable

  26. # 注意, 顺便提一下,

  27. #+ 这个字符串变量可能会被设置一些非法字符.

  28. : ${ThisVariable?}

  29. echo "Value of ThisVariable is $ThisVariable".

  30. echo

  31. echo

  32.  
  33.  
  34. : ${ZZXy23AB?"ZZXy23AB has not been set."}

  35. # 如果变量ZZXy23AB没有被设置的话,

  36. #+ 那么这个脚本会打印一个错误信息, 然后结束.

  37.  
  38. # 你可以自己指定错误消息.

  39. # : ${variablename?"ERROR MESSAGE"}

  40.  
  41.  
  42. # 等价于: dummy_variable=${ZZXy23AB?}

  43. # dummy_variable=${ZZXy23AB?"ZXy23AB has not been set."}

  44. #

  45. # echo ${ZZXy23AB?} >/dev/null

  46.  
  47. # 使用命令"set -u"来比较这些检查变量是否被设置的方法.

  48. #

  49.  
  50. echo "You will not see this message, because script already terminated."

  51.  
  52. HERE=0

  53. exit $HERE # 不会在这里退出.

  54.  
  55. # 事实上, 这个脚本将会以返回值1作为退出状态(echo $?).

2.变量长度/子串删除

${#var} 字符串长度(变量$var得字符个数)。对于array来说,${#array}表示的是数组中第一个元素的长度.。

变量长度:

 
  1. #!/bin/bash

  2.  
  3. E_NO_ARGS=65

  4.  
  5. if [ $# -eq 0 ] # 这个演示脚本必须有命令行参数.

  6. then

  7. echo "Please invoke this script with one or more command-line arguments."

  8. exit $E_NO_ARGS

  9. fi

  10.  
  11. var01=abcdEFGH28ij

  12. echo "var01 = ${var01}"

  13. echo "Length of var01 = ${#var01}"

  14. # 现在, 让我们试试在变量中嵌入一个空格.

  15. var02="abcd EFGH28ij"

  16. echo "var02 = ${var02}"

  17. echo "Length of var02 = ${#var02}"

  18.  
  19. echo "Number of command-line arguments passed to script = ${#@}"

  20. echo "Number of command-line arguments passed to script = ${#*}"

  21.  
  22. exit 0

${var#Pattern}, ${var##Pattern} 从变量$var的开头删除最短或最长匹配$Pattern的子串。

“#”表示匹配最短,“##”表示匹配最长。

 
  1. strip_leading_zero2 () # 去掉开头可能存在的0(也可能有多个0), 因为如果不取掉的话,

  2. { # Bash就会把这个值当作8进制的值来解释.

  3. shopt -s extglob # 打开扩展的通配(globbing).

  4. local val=${1##+(0)} # 使用局部变量, 匹配最长连续的一个或多个0.

  5. shopt -u extglob # 关闭扩展的通配(globbing).

  6. _strip_leading_zero2=${val:-0}

  7. # 如果输入为0, 那么返回0来代替"".

  8. }

${var%Pattern}, ${var%%Pattern} 从变量$var的结尾删除最短或最长匹配$Pattern的子串。

“%”表示匹配最短,“%%”表示匹配最长。

3.变量扩展/子串替换

${var:pos} 变量var从位置pos开始扩展, 也就是pos之前的字符都丢弃。

${var:pos:len} 变量var从位置pos开始,并扩展len个字符。

${var/Pattern/Replacement} 使用Replacement来替换变量var中第一个匹配Pattern的字符串。

${var//Pattern/Replacement} 全局替换。所有在变量var匹配Pattern的字符串,都会被替换为Replacement。

 
  1. #!/bin/bash

  2.  
  3. var1=abcd-1234-defg

  4. echo "var1 = $var1"

  5.  
  6. t=${var1#*-*}

  7. echo "var1 (with everything, up to and including first - stripped out) = $t"

  8. # t=${var1#*-} 也一样,

  9. #+ 因为#匹配最短的字符串,

  10. #+ 同时*匹配任意前缀, 包括空字符串.

  11. # (感谢, Stephane Chazelas, 指出这点.)

  12.  
  13. t=${var1##*-*}

  14. echo "If var1 contains a \"-\", returns empty string... var1 = $t"

  15.  
  16.  
  17. t=${var1%*-*}

  18. echo "var1 (with everything from the last - on stripped out) = $t"

${var/#Pattern/Replacement} 如果变量var的前缀匹配Pattern,那么就使用Replacement来替换匹配到Pattern的字符串。

${var/%Pattern/Replacement} 如果变量var的后缀匹配Pattern,那么就使用Replacement来替换匹配到Pattern的字符串。

 
  1. #!/bin/bash

  2. # var-match.sh:

  3. # 对字符串的前缀和后缀进行模式替换的一个演示.

  4.  
  5. v0=abc1234zip1234abc # 变量原始值.

  6. echo "v0 = $v0" # abc1234zip1234abc

  7. echo

  8.  
  9. # 匹配字符串的前缀(开头).

  10. v1=${v0/#abc/ABCDEF} # abc1234zip1234abc

  11. # |-|

  12. echo "v1 = $v1" # ABCDEF1234zip1234abc

  13. # |----|

  14.  
  15. # 匹配字符串的后缀(结尾).

  16. v2=${v0/%abc/ABCDEF} # abc1234zip123abc

  17. # |-|

  18. echo "v2 = $v2" # abc1234zip1234ABCDEF

  19. # |----|

  20.  
  21. echo

  22.  
  23. # ----------------------------------------------------

  24. # 必须匹配字符串的开头或结尾,

  25. #+ 否则是不会产生替换结果的.

  26. # ----------------------------------------------------

  27. v3=${v0/#123/000} # 匹配, 但不是在开头.

  28. echo "v3 = $v3" # abc1234zip1234abc

  29. # 不会发生替换.

  30. v4=${v0/%123/000} # 匹配, 但不是在结尾.

  31. echo "v4 = $v4" # abc1234zip1234abc

  32. # 不会发生替换.

  33.  
  34. exit 0

  35. ${!varprefix*}, ${!varprefix@} 匹配所有之前声明过的,并且以varprefix开头的变量。

  36. xyz23=whatever

  37. xyz24=

  38.  
  39. a=${!xyz*} # 展开所有以"xyz"开头的, 并且之前声明过的变量名.

  40. echo "a = $a" # a = xyz23 xyz24

  41. a=${!xyz@} # 同上.

  42. echo "a = $a" # a = xyz23 xyz24

  43.  
  44. # Bash, 版本2.04, 添加了这个功能.

四、指定变量的类型: 使用declare或者typeset

1.declare/typeset选项

选项 说明
-r 只读
-i 整型
-a 数组
-f 函数
-x export

2.使用declare来指定变量的类型

 
  1. #!/bin/bash

  2.  
  3. func1 ()

  4. {

  5. echo This is a function.

  6. }

  7.  
  8. declare -f # 列出前面定义的所有函数.

  9.  
  10. echo

  11.  
  12. declare -i var1 # var1是个整型变量.

  13. var1=2367

  14. echo "var1 declared as $var1"

  15. var1=var1+1 # 整型变量的声明并不需要使用'let'命令.

  16. echo "var1 incremented by 1 is $var1."

  17. # 尝试修改一个已经声明为整型变量的值.

  18. echo "Attempting to change var1 to floating point value, 2367.1."

  19. var1=2367.1 # 产生错误信息, 并且变量并没有被修改.

  20. echo "var1 is still $var1"

  21.  
  22. echo

  23.  
  24. declare -r var2=13.36 # 'declare'允许设置变量的属性,

  25. #+ 同时给变量赋值.

  26. echo "var2 declared as $var2" # 试图修改只读变量的值.

  27. var2=13.37 # 产生错误消息, 并且从脚本退出.

  28.  
  29. echo "var2 is still $var2" # 将不会执行到这行.

  30.  
  31. exit 0 # 脚本也不会从此处退出.

五、变量的间接引用

1.间接引用

假设一个变量的值是第二个变量的名字。如果a=letter_of_alphabet并且letter_of_alphabet=z,

它被称为间接引用。我们能够通过引用变量a来获得z,它使用eval var1=\$$var2这种不平常的形式。

 
  1. #!/bin/bash

  2. # 访问一个以另一个变量内容作为名字的变量的值.(译者注: 怎么译都不顺)

  3.  
  4. a=letter_of_alphabet # 变量"a"的值是另一个变量的名字.

  5. letter_of_alphabet=z

  6.  
  7. echo

  8.  
  9. # 直接引用.

  10. echo "a = $a" # a = letter_of_alphabet

  11.  
  12. # 间接引用.

  13. eval a=\$$a

  14. echo "Now a = $a" # 现在 a = z

  15.  
  16. echo

  17.  
  18. # 现在, 让我们试试修改第二个引用的值.

  19.  
  20. t=table_cell_3

  21. table_cell_3=24

  22. echo "\"table_cell_3\" = $table_cell_3" # "table_cell_3" = 24

  23. echo -n "dereferenced \"t\" = "; eval echo \$$t # 解引用 "t" = 24

  24. # 在这个简单的例子中, 下面的表达式也能正常工作么(为什么?).

  25. # eval t=\$$t; echo "\"t\" = $t"

  26.  
  27. echo

  28.  
  29. t=table_cell_3

  30. NEW_VAL=387

  31. table_cell_3=$NEW_VAL

  32. echo "Changing value of \"table_cell_3\" to $NEW_VAL."

  33. echo "\"table_cell_3\" now $table_cell_3"

  34. echo -n "dereferenced \"t\" now "; eval echo \$$t

  35. # "eval" 带有两个参数 "echo" 和 "\$$t" (与$table_cell_3等价)

  36.  
  37. echo

  38.  
  39. exit 0

2.传递一个间接引用给awk

 
  1. #!/bin/bash

  2.  
  3. # 这是"求文件中指定列的总和"脚本的另一个版本,

  4. #+ 这个脚本可以计算目标文件中指定列(此列的内容必须都是数字)的所有数字的和.

  5. # 这个脚本使用了间接引用.

  6.  
  7. ARGS=2

  8. E_WRONGARGS=65

  9.  
  10. if [ $# -ne "$ARGS" ] # 检查命令行参数的个数是否合适.

  11. then

  12. echo "Usage: `basename $0` filename column-number"

  13. exit $E_WRONGARGS

  14. fi

  15.  
  16. filename=$1

  17. column_number=$2

  18.  
  19. #===== 在这一行上边的部分, 与原始脚本是相同的 =====#

  20.  
  21. # 多行的awk脚本的调用方法为: awk ' ..... '

  22.  
  23. # awk脚本开始.

  24. # ------------------------------------------------

  25. awk "

  26.  
  27. { total += \$${column_number} # 间接引用

  28. }

  29. END {

  30. print total

  31. }

  32.  
  33. " "$filename"

  34. # ------------------------------------------------

  35. # awk脚本结束.

  36.  
  37. exit 0

六、双圆括号结构

1.简介

与let命令很相似,((...)) 结构允许算术扩展和赋值。

如,a=$(( 5 + 3 )),将把变量“a”设为“5 + 3”,或者8。

2.C语言风格的变量操作

 
  1. #!/bin/bash

  2. # 使用((...))结构操作一个变量, C语言风格的变量操作.

  3.  
  4. echo

  5.  
  6. (( a = 23 )) # C语言风格的变量赋值, "="两边允许有空格.

  7. echo "a (initial value) = $a"

  8.  
  9. (( a++ )) # C语言风格的后置自加.

  10. echo "a (after a++) = $a"

  11.  
  12. (( a-- )) # C语言风格的后置自减.

  13. echo "a (after a--) = $a"

  14.  
  15.  
  16. (( ++a )) # C语言风格的前置自加.

  17. echo "a (after ++a) = $a"

  18.  
  19. (( --a )) # C语言风格的前置自减.

  20. echo "a (after --a) = $a"

  21.  
  22. echo

  23.  
  24. ########################################################

  25. # 注意: 就像在C语言中一样, 前置或后置自减操作

  26. #+ 会产生一些不同的副作用.

  27.  
  28. n=1; let --n && echo "True" || echo "False" # False

  29. n=1; let n-- && echo "True" || echo "False" # True

  30.  
  31. echo

  32.  
  33. (( t = a<45?7:11 )) # C语言风格的三元操作.

  34. echo "If a < 45, then t = 7, else t = 11."

  35. echo "t = $t " # Yes!

  36.  
  37. echo

  38.  
  39. # 你也可以参考一些 "for" 和 "while" 循环中使用((...))结构的例子.

  40.  
  41. exit 0

个人分类: shell

猜你喜欢

转载自blog.csdn.net/kwame211/article/details/81080932
今日推荐