shell处理命令行选项和参数
Synopsis: shell编程时经常要处理用户输入,除了使用read命令获取数据外,最直接的是从命令行参数和选项处来获取用户输入。命令行参数允许用户运行脚本时直接从命令行输入数据,脚本通过位置参数来取回命令行参数并将它们赋值给位置变量。case结合shift命令基本上能处理大部分情形的选项和参数,但是不能正确处理多个短选项合并的情形。外部命令getopt和内置命令getopts可以很好的处理命令行选项,但不支持长选项,且getopt不能正确处理选项后面跟带空格的参数值
1. 命令行参数
1.1 位置变量
向shell脚本传递数据的最基本方式是使用命令行参数
(command line parameters),bash shell将在命令行中输入的所有参数(以空格分隔)赋值给一些特殊变量,这些变量称为位置变量
(positional parameter),其中$0
为shell执行的程序的名称,$1
为第一个参数,$2
为第二个参数,依次类推,直到$9
为第九个参数。在第9个变量之后,必须使用大括号将变量括起来,如${10}
1. 有两个命令行参数,$1被赋值10,$2被赋值20 [root@CentOS ~]# ./test.sh 10 20 2. 传递包含空格的参数值,必须使用引号(单引号和双引号均可),$1被赋值Hello World [root@CentOS ~]# ./test.sh "Hello World"
在shell脚本中使用命令行参数前,要对参数进行检查,确保参数变量中确实存在数据,否则脚本可能会产生错误:
1. 脚本内容 #!/bin/bash if [ -n "$1" ]; then echo "hello $1, glad to meet you." else echo "Sorry, you didn't identify yourself." fi 2. 测试 [root@CentOS ~]# ./test.sh Sorry, you didn't identify yourself. [root@CentOS ~]# ./test.sh wangy hello wangy, glad to meet you.
或者使用[[ ]]
,里面的参数变量可以不用双引号
包括起来:
1. 脚本内容 #!/bin/bash if [[ -n $1 ]]; then echo "hello $1, glad to meet you." else echo "Sorry, you didn't identify yourself." fi 2. 测试 [root@CentOS ~]# ./test.sh Sorry, you didn't identify yourself. [root@CentOS ~]# ./test.sh wangy hello wangy, glad to meet you.
如果条件中使用[ ]
,且参数没有使用双引号,那么当用户不传参数的时候,$1为空,这时就会变成if [ -n ];
,结果是错误的,而有双引号时是if [ -n "" ];
:
1. 脚本内容 #!/bin/bash if [ -n $1 ]; then echo "hello $1, glad to meet you." else echo "Sorry, you didn't identify yourself." fi 2. 测试 [root@CentOS ~]# ./test.sh hello , glad to meet you. # 错误 [root@CentOS ~]# ./test.sh wangy hello wangy, glad to meet you.
或者,可以加一个辅助字符串来进行比较,如if [ x$1 != x ]
:
1. 脚本内容 #!/bin/bash if [ x$1 != x ]; then echo "hello $1, glad to meet you." else echo "Sorry, you didn't identify yourself." fi 2. 测试 [root@CentOS ~]# ./test.sh Sorry, you didn't identify yourself. [root@CentOS ~]# ./test.sh wangy hello wangy, glad to meet you.
1.2 参数计数
特殊变量$#
中存储了执行脚本时包含的命令行参数的个数,最后一个
命令行参数值不是${$#}
,因为不能在大括号中使用美元符号$
,必须将它换成感叹号!
,即${!#}
1. 脚本内容 #!/bin/bash if [ $# -ne 2 ]; then echo "Usage: test.sh a b" else total=$[ $1 + $2 ] echo "The total is $total" fi 2. 测试 [root@CentOS ~]# ./test.sh Usage: test.sh a b [root@CentOS ~]# ./test.sh 10 Usage: test.sh a b [root@CentOS ~]# ./test.sh 10 20 The total is 30
1.3 获取所有参数
特殊变量$*
和$@
都包含所有命令行参数,它们不被双引号" "
包括时是一样的。不带双引号时,两种都不建议使用,因为参数包含空格或通配符,它们就可能意外中断
1. 脚本内容 #!/bin/bash vim $* # 这里换成vim $@也一样 2. 测试,假设要打开当前目录下的foo.txt、bar.txt、hello\ world.txt这三个文件,最后一个文件名有空格,但是参数传递给脚本后,被识别成要打开foo.txt、bar.txt、hello、world.txt四个文件,这是错误的(vim打开多个文件,可以用:ls查看打开的文件列表) [root@CentOS ~]# ./test.sh foo.txt bar.txt "hello world.txt"
但是当它们被双引号包括时是有区别的,"$*"
把所有命令行参数当作一个字串
,每个参数的值由IFS
特殊变量的第一个字符分隔,即"$1c$2c..."
,其中c
是IFS
变量值的第一个字符(默认是空格)。如果IFS为空IFS=
,参数之间直接连接,即"$1$2..."
。如果IFS未设置unset IFS
,则参数由空格分隔。
而"$@"
把命令行参数当作多个字串
,每个参数都会扩展为单独的字串,即"$1" "$2" ...
。如果双引号扩展出现在字串中,则第一个参数的扩展与原始字串的开始部分连接,最后一个参数的扩展连接到原始字串的最后部分。
$*
、$@
、"$*"
、"$@"
分别被扩展成几个字串?
1. 脚本内容 #!/bin/bash function main { echo 'MAIN sees ' $# ' args' } main $* main $@ main "$*" main "$@" 2. 测试 [root@CentOS ~]# ./test.sh foo bar "hello world" MAIN sees 4 args # 四个参数,分别是foo、bar、hello、world MAIN sees 4 args # 四个参数,分别是foo、bar、hello、world MAIN sees 1 args # 一个参数,即"foo bar hello world"(引号不算在内) MAIN sees 3 args # 三个参数,分别是foo、bar、"hello world"(引号不算在内),只有它是正确的
如果需要分开成多个字串,请使用
"$@"
; 如果需要将参数当作一个字串传给其它程序如grep,请使用"$*"
1. 脚本内容 #!/bin/bash echo "*** \$* and \$@ are not put into double quotes(\" \") ***" count=1 for param in $*; do echo "\$* Parameters #$count = '$param'" count=$[ $count + 1 ] done count=1 for param in $@; do echo "\$@ Parameters #$count = '$param'" count=$[ $count + 1 ] done echo "---------------------------" echo "*** IFS is set to '+fuck' ***" IFS="+fuck" count=1 for param in "$*"; do echo "\"\$*\" Parameters #$count = '$param'" count=$[ $count + 1 ] done count=1 for param in "$@"; do echo "\"\$@\" Parameters #$count = '$param'" count=$[ $count + 1 ] done echo "---------------------------" echo "*** IFS is set to null ***" IFS= count=1 for param in "$*"; do echo "\"\$*\" Parameters #$count = '$param'" count=$[ $count + 1 ] done count=1 for param in "$@"; do
0 条评论
评论者的用户名
评论时间暂时还没有评论.