shell处理命令行选项和参数

  • 原创
  • Madman
  • /
  • /
  • 0
  • 1886 次阅读

shell处理命令行选项和参数-min.png

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...",其中cIFS变量值的第一个字符(默认是空格)。如果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 "$@
                                
                            
未经允许不得转载: LIFE & SHARE - 王颜公子 » shell处理命令行选项和参数

分享

作者

作者头像

Madman

如需 Linux / Python 相关问题付费解答,请按如下方式联系我

0 条评论

暂时还没有评论.

专题系列

热门文章