1. bash shell脚本中的位置变量
1. 有些脚本运行时是需要输入参数的,在shell脚本中加入指定的位置变量,脚本会在运行时读取位置变量对应的参数,位置变量表示方法如下:
(1)$0:表示脚本自身
(2)$(basename $0):当我们使用位置变量$0时,表示将脚本自身名称作为变量值传递给$0,但是它会传递完整的脚本路径,当我们仅需要脚本的基名的时候,可以使用$(basename $0)来实现
(3)$1-$9:表示脚本后跟的参数的位置,$1表示第一个参数,$2表示第二个参数以此类推;
(4)${#}:#表示大于9的数字,当位置大于9时需使用${}的方式来表示位置
(5)${!#}:表示脚本最后一个参数作为变量传递给${!#}
(6)$#:表示参数个数统计,$#变量会计算脚本所跟参数的个数
(7)$*:表示脚本后跟随的所有参数,但是它会把这些参数当做一个整体传递给$*变量
(8)[email protected]:与$*类似,同样是将脚本后所跟随的所有参数传递给[email protected]变量,但是会把每个变量做为单个个体依次传递给[email protected]。
(9)含空格的参数表示方法:位置变量取值时默认以空格作为分割,当参数包含空格时,需使用""将该参数引起来,这样就可以当成一个独立的参数传递给脚本
(10)shift:脚本参数位移,当在脚本中使用shift时表示将参数的位置向左移动一位
(11)shift n:n用数字表示,shift n表示将参数将左移动n位
2. bash shell脚本位置变量使用示例
2.1 $0
[[email protected] test]# vi test1.sh #!/bin/bash #Testing the $0 parameter # echo "The zero parameter" is set to: $0 ~ "test1.sh" [New] 5L, 81C written [[email protected] test]# chmod u+x test1.sh [[email protected] test]# ./test1.sh The zero parameter is set to: ./test1.sh
根据上述脚本可看出$0的取值为脚本名 ./test1.sh
2.2 $(basename $0)
[[email protected] test]# vi test2.sh #!/bin/bash #Testing the $(basename $0) parameter # echo "The zero parameter" is set to: $(basename $0) ~ "test2.sh" 5L, 105C written [[email protected] test]# ./test2.sh The zero parameter is set to: test2.sh
根据上述示例可看出使用$(basename $0)后,取得的脚本名仅为脚本名本身,不包含路径
2.3 $1-$9
[[email protected] test]# vi test3.sh #!/bin/bash #USing one command line parameter # factorial=1 for (( number=1; number <= $1; number++ )) do factorial=$[ $factorial * $number ] done echo The factorial of $1 is $factorial ~ ~ "test3.sh" 9L, 188C written [[email protected] test]# ./test3.sh 4 The factorial of 4 is 24
根据上述脚本可看出脚本参数4被赋予给了位置变量$1
[[email protected] test]# vi test4.sh #!/bin/bash #Testing tow command lin parameters # if [ $# -ge 3 ] then echo "Please input only tow parameters" elif [ $# -eq 2 ] then if [ $1 -gt $2 ] then echo "$1 is greater than $2" elif [ $1 -eq $2 ] then echo "$1 is equal to $2" else echo "$1 is less than $2" fi else echo "The character you entered is invalid, please enter the number" fi ~ ~ ~ ~ "test4.sh" 20L, 359C written [[email protected] test]# ./test4.sh 4 5 4 is less than 5
通过上述脚本可以看出$1和$2分别对应位置1和位置2的参数。
2.4 ${#}
当参数个数大于9时,位置变量用${#}表示,#表示大于9的数字
[[email protected] test]# vi test5.sh #!/bin/bash #handing lots of parameters # total=$[ ${10} * ${11} ] echo The tenth parameter is ${10} echo The eleventh parameter is ${11} echo The total is $total ~ ~ "test5.sh" 7L, 163C written [[email protected] test]# ./test5.sh 1 2 3 4 5 6 7 8 9 10 11 The tenth parameter is 10 The eleventh parameter is 11 The total is 110
2.5 $# ${!#}
$#表示参数的个数,${!#}表示最后一个参数
[[email protected] test]# vi test6.sh #!/bin/bash #Grabbing the last parameter # params=$# echo The total number of parameters is $# echo The last parameter is ${!#} ~ ~ "test6.sh" 6L, 128C written [[email protected] test]# ./test6.sh 1 2 4 6 8 9 10 4 The total number of parameters is 8 The last parameter is 4
根据上述脚本和执行结果和看出$#最后显示的是参数的总个数,为8个,${!#}显示的是最后一个参数,为4。${!#}还有一个特殊特性,当脚本后没有参数时将返回脚本名。
2.6 $* [email protected]
$*和[email protected]都表示所有参数,但是$*表示将所有参数当做一个整体传递给$*,而[email protected]则表示将每个参数按顺序一个个传递给[email protected]
[[email protected] test]# vi test7.sh #!/bin/bash #Testing $* and [email protected] # count=1 # for params in "$*" do echo "\$* Paramter #$count = $params" count=$[ $count + 1 ] done # # count=1 for params in "[email protected]" do echo "\[email protected] Parameter #$conut = $params" count=$[ $count + 1 ] done ~ ~ ~ "test7.sh" 18L, 234C written [[email protected] test]# ./test7.sh rich barbara katie jessica $* Paramter #1 = rich barbara katie jessica [email protected] Parameter # = rich [email protected] Parameter # = barbara [email protected] Parameter # = katie [email protected] Parameter # = jessica
根据上述脚本可以看到我们分别为$*和$#设置了for循环,从队列$*读取的变量值是将参数作为一个整体,而从[email protected]中是逐个参数船体给[email protected]
2.7 shift n
在shell脚本中shift的作用是将指定位置的参数向左移动,n为移动的位置数,如果没有设置n,则默认为1
[[email protected] test]# vi test8.sh #!/bin/bash #Testing shift # count=1 for params in "[email protected]" do echo "#$count = $1" count=$[ $count + 1 ] shift done ~ ~ "test8.sh" 10L, 115C written [[email protected] test]# ./test8.sh rich barbara katie jessica #1 = rich #2 = barbara #3 = katie #4 = jessica
根据上述脚本可看出每一执行完一轮循环shift都会将参数左移一位,$1位置的参数在位移后会丢失。$1会读取原$1位置的后一位参数。
[[email protected] test]# vi test9.sh #!/bin/bash #Demonstrating a multi-position shift # echo "The original parameter: $*" shift 2 echo "Here‘s the new first parameter: $1" ~ ~ "test9.sh" [New] 6L, 136C written [[email protected] test]# chmod u+x test9.sh [[email protected] test]# ./test9.sh 1 2 3 4 5 The original parameter: 1 2 3 4 5 Here‘s the new first parameter: 3
根据上述脚本可看出当使用shift 2 后,参数向左移动了2位,所有移动后的$1为3
3. 处理命令行选项
3.1 处理简单选项
可以使用while循环检查选项,使用case命令按照条件输出选项所对应的操作。
[[email protected] test]# vi test1.sh #!/bin/bash #Testing simple parameter processing # while [ -n "$1" ] do case "$1" in -a ) echo "Found the -a option" ;; -b ) echo "Found the -b option" ;; -c ) echo "Found the -c option" ;; * ) echo "The $1 is not an option" ;; esac shift done ~ ~ ~ [[email protected] test]# ./test1.sh -a -b -c -d Found the -a option Found the -b option Found the -c option The -d is not an option
3.2 分离选项和参数
可使用使用 -- 号来分离选项和参数当遇到 -- 时终止while循环,同时把 -- 使用shift命令移除
[[email protected] test]# vi test2.sh #!/bin/bash #Testing simple parameter processing # while [ -n "$1" ] do case "$1" in -a ) echo "Found the -a option" ;; -b ) echo "Found the -b option" ;; -c ) echo "Found the -c option" ;; -- ) shift break ;; * ) echo "The $1 is not an option" ;; esac shift done # count=1 for parameter in "[email protected]" do echo "The #$parameter is a parameter" count=$[ $count + 1 ] done ~ ~ "test2.sh" 22L, 381C written [[email protected] test]# ./test2.sh -c -b test1 test2 test3 Found the -c option Found the -b option The test1 is not an option The test2 is not an option The test3 is not an option [[email protected] test]# ./test2.sh -c -a -- test1 test2 test3 Found the -c option Found the -a option The #test1 is a parameter The #test2 is a parameter The #test3 is a parameter
3.3 处理带参数的选项
[[email protected] test]# vi test3.sh #!/bin/bash # extracting command line options and values # while [ -n "$1" ] do case "$1" in -a) echo "Found the -a options";; -b) parameter="$2" echo "Found the -b options , with parameter values $parameter" shift;; -c) echo "Found the -c options";; --) shift break;; *) echo "$1 is not options";; esac shift done # count=1 for parameter in "[email protected]" do echo #$parameter is a parameter count=$[ $count + 1 ] done ~ ~ "test3.sh" 24L, 442C written [[email protected] test]# ./test3.sh -a -b test1 -d Found the -a options Found the -b options , with parameter values test1 -d is not options
3.4 getopt命令
getopt命令可以接受任何选项和参数,并将他们转换成相应的格式
格式:getopt OPTSRING parameter
带参数的选项后跟:
示例:
[[email protected] test]# getopt ab:cd -a -b test1 -cd test2 test3 test4 -a -b test1 -c -d -- test2 test3 test4
要在脚本中使用getopt命令,需要使用set命令
示例:(-q 命令表示忽略错误提示,--会将命令行参数替换成set的命令行值)
set -- $(getopt -q -ab:cd "[email protected]")
脚本示例如下:
[[email protected] test]# vi test4.sh #!/bin/bash #Extract command line options & values with getopt # set -- $(getopt -q ab:cd "[email protected]") while [ -n "$1" ] do case "$1" in -a) echo "Found the -a options";; -b) parameter=$2 echo "Found the -b options with parameter value $parameter" shift;; -c) echo "Found the -c options";; -d) echo "Found the -d options";; --) shift break;; *) echo "$1 is not option";; esac shift done # count=1 for parameter in "[email protected]" do echo "The #$parameter is a parameter" count=$[ $count + 1 ] done ~ "test4.sh" 26L, 516C written [[email protected] test]# ./test4.sh -a -b test1 -c -d test3 test4 test5 test6 Found the -a options Found the -b options with parameter value ‘test1‘ Found the -c options Found the -d options The #‘test3‘ is a parameter The #‘test4‘ is a parameter The #‘test5‘ is a parameter The #‘test6‘ is a parameter
根据上述可看出getopt命令可以自动识别参数、选项,无需使用--来隔开参数。
但是getopt存在缺陷,例如同样运行上述脚本执行以下参数,结果可能会出现偏差
示例:
[[email protected] test]# ./test4.sh -a -b "test1 test2" -cd test3 test4 Found the -a options Found the -b options with parameter value ‘test1 test2‘ is not option #test1和test2同为-b选项的参数,但仅能识别test1,getopt不能识别"" Found the -c options Found the -d options The #‘test3‘ is a parameter The #‘test4‘ is a parameter
通过上述脚本执行结果可发现getopt不能识别“”,用“”引起来的参数不会被当成同一个参数来对待。
3.5 getopts
getopts命令相当于getopt命令的升级版,但是getopts和getopt存在乳如下差异:
(1)getopt会将所有输入选项和参数一次性输出,但是getopts一次只处理一个参数或选项,输出完成后会返回一个大于0的退出码;
(2)getopts忽略错误的方式是在OPTstring之前加:,而getopt忽略错误的方式是加-q选项
命令格式: getopts OPTSTRING parameter
(3)getopts会将“”下的参数当成一个参数来输出
(4)getopts会自动移除--选项,所以case中的条件无需指定--
(5)getopts可以将选项和参数输入到一起,无需空格隔开
(6)对于未识别的选项和参数会返回?
(7)getopts命令会用到两个环境变量。如果选项需要跟一个参数值,OPTARG环境变量就会保存这个值。OPTIND环境变量保存了参数列表中getopts正在处理的参数位置。这样你就能在处理完选项之后继续处理其他命令行参数
示例1:
[[email protected] test]# vi test5.sh #!/bin/bash #simple demonstration of the getopts command # while getopts :ab:c opt do case "$opt" in a) echo "Found the -a option";; b) echo "Found the -b option with VALUE $OPTARG";; c) echo "Found the -c option";; *) echo "Unknow option : $opt ";; esac done ~ "test5.sh" 12L, 271C written [[email protected] test]# ./test5.sh -a -b test1 -c Found the -a option Found the -b option with VALUE test1 Found the -c option [[email protected] test]# ./test5.sh -a -b "test1 test2" -c Found the -a option Found the -b option with VALUE test1 test2 Found the -c option [[email protected] test]# ./test5.sh -d Unknow option : ?
getopts命令知道何时停止处理选项,并将参数留给你处理。在getopts处理每个选项时,它会将OPTIND环境变量值增一。在getopts完成处理时,你可以使用shift命令和OPTIND值来移动参数。
示例:
[[email protected] test]# vi test6.sh #!/bin/bash #Processing options & parameters with getopts # while getopts :ab:cd opt do case "$opt" in a) echo "Found the -a option";; b) echo "Found the -b option with parameter is $OPTARG";; c) echo "Found the -c option";; d) echo "Found the -d option";; *) echo "Unknow options";; esac done shift $[ $OPTIND - 1 ] # count=1 for parameter in "[email protected]" do echo "Parameter #$count : $parameter" count=$[ $count + 1 ] done ~ "test6.sh" 21L, 431C written [[email protected]alhost test]# ./test6.sh -a -b test1 -c -d test3 test4 Found the -a option Found the -b option with parameter is test1 Found the -c option Found the -d option Parameter #1 : test3 Parameter #2 : test4
3.6 选项标准化
linux中有一些比较通用的选项,如果我们的脚本支持这些选项对用户来说将变的更友好
-a : 显示所有对象
-c : 生成一个计数器
-d : 指定一个目录
-e : 扩展一个对象
-f : 指定一个输入数据的文件
-h : 显示该命令的帮助信息
-i : 忽略文本大小写
-l : 输出长格式版本
-n : 使用非交互模式输出(批处理)
-o : 将输出内容重定向输出至指定文件
-q : 以安静模式运行
-r : 递归的处理目录和文件
-s : 以安静模式运行
-v :生成详细输出
-x : 排除某个对象
-y : 对所有问题都回答YES
4. 获得用户的输入
4.1 获得用户的基本输入
可以使用read命令获得用户的输入
示例
[[email protected] test]# vi test7.sh #!/bin/bash #Testing the read command # echo -n "Enter your name:" read name echo "Hello $name , welcome to my program ! " ~ ~ "test7.sh" [New] 6L, 123C written [[email protected] test]# chmod o+x test7.sh [[email protected] test]# ./test7.sh Enter your name:liuxingyue Hello liuxingyue , welcome to my program !
根据上述脚本可看出read 可以将接受用户输入的参数赋予给read命令后的变量,echo后的-n参数表示在字符串末尾输出换行符;
初此之外read 还可以使用-p命令接受用户输入的参数
示例
[[email protected] test]# vi test8.sh #!/bin/bash #Testing "read -p" command # read -p "Please input your age :" age day=$[ $age * 365 ] echo "That makes your over $day days old !" ~ "test8.sh" 6L, 144C written [[email protected] test]# ./test8.sh Please input your age :33 That makes your over 12045 days old !
上述示例处理的只是单个变量,如果用户输入多个参数,read可以将参数依次匹配到指定变量,如果输入参数个数比变量个数多,则会将最后的参数全部匹配到最后的变量中
示例
[[email protected] test]# vi test9.sh #!/bin/bash # ENtering multiple variables # read -p "Enter your name :" first last echo "Welcome $first $last..." ~ ~ "test9.sh" [New] 5L, 114C written [[email protected] test]# chmod o+x test9.sh [[email protected] test]# ./test9.sh Enter your name :liu xingyue hehe Welcome liu xingyue hehe...
read命令会将用户输入的参数存入到REPLY变量中,如果read不指定变量,使用$REPLY变量也可以。
示例
[[email protected] test]# ./test10.sh Enter your name :wangyanglin ^H wangyanglin , Wlecome to my program [[email protected] test]# vi test10.sh #!/bin/bash #Testing $REPLY # read -p "Enter your name :" echo "$REPLY , Wlecome to my program" ~ ~ "test10.sh" 5L, 97C written [[email protected] test]# ./test10.sh Enter your name :hah heh hoh hah heh hoh , Wlecome to my program [[email protected] test]# ^C [[email protected] test]#
4.2 输入超时控制
read -t #命令通过-t选项指定一个计数器,#表示秒数,加入#为5,则表示5秒之内如果用户没有输入会自动退出脚本并返回一个非零的退出状态码
示例:
[[email protected] test]# vi test11.sh #!/bin/bash #Test the -t option # read -t 5 -p "Enter your name :" echo "$REPLY , Welcome to my program" ~ ~ ~ "test11.sh" [New] 5L, 105C written [[email protected] test]# chmod o+x test11.sh [[email protected] test]# ./test11.sh Enter your name : , Welcome to my program
read -n# 选项可以定义输入的字符个数,#为1,则表示仅只能输入一个字符。
[[email protected] test]# vi test12.sh #!/bin/bash #getting just one character of input read -n1 -p"Do you want contine [Y/N] ?" case $REPLY in y|Y) echo "Fine,contine to .......";; n|N) echo "OK , bye !" exit;; *) echo "Input error" exit;; esac echo "This is the end of the script" ~ "test12.sh" 11L, 257C written [[email protected] test]# ./test12.sh Do you want contine [Y/N] ?yFine,contine to ....... This is the end of the script [[email protected] test]# ./test12.sh Do you want contine [Y/N] ?nOK , bye ! [[email protected] test]# ./test12.sh Do you want contine [Y/N] ?eInput error
4.3 隐藏式输入
read命令的 -s参数可以实现输入隐藏,脚本运行时你输入的内容不会显示出来(实际上是显示的,只是颜色与背景色一样),一般会用于输入密码或者其他场景。
示例:
[[email protected] test]# vi test13.sh #!/bin/bash #Testing the "-s" option. # read -s -p "Please input your password:" pass echo "Your password is $pass" ~ ~ "test13.sh" 5L, 116C written [[email protected] test]# ./test13.sh Please input your password:Your password is nihao
4.4 read读取文本输入,可以使用while循环,文本输入完成以后,自动结束命令
示例:
[[email protected] test]# vi test14.sh #!/bin/bash #Testing text input with read command # count=1 cat test | while read line do echo "Line #$count : $line" count=$[ $count +1 ] done echo "Finished processing the file." ~ ~ ~ "test14.sh" [New] 10L, 183C written [[email protected] test]# cat test ck brown dog jumps over the lazy fox. This is a test, this is only a test. O Romeo, Romeo! Wherefore art thou Romeo? [[email protected] test]# ./test14 -bash: ./test14: No such file or directory [[email protected] test]# ./test14.sh Line #1 : ck brown dog jumps over the lazy fox. Line #2 : This is a test, this is only a test. Line #3 : O Romeo, Romeo! Wherefore art thou Romeo? Finished processing the file.