文章目录
- 1. 命令行参数
-
- 1.1 读取参数
- 1.2 读取脚本名--`$0`
- 1.3 测试参数--`-n`
- 2.特殊参数变量
-
- 2.1 参数统计--`$#`
- 2.2 抓取所有数据--`$*`和`[email protected]`[遍历命令行的绝妙方法]
- 3.移动变量--shift命令[遍历命令行参数的另一个好方法]
- 4.处理选项
-
- 4.1 查找选项
- 4.2 使用getopt命令-格式化命令行选项和参数
- 4.3 使用更高级的getopts--避开getopt命令的劣势扩展了一些功能
- 5.将选项标准化
- 6.获得用户输入--`read`
-
- 6.1 基本的获取
- 6.2 超时--read需要超时判断
- 6.3 隐藏方式读取--`-s`典型应用于密码输入上
- 6.4 从文件读取
1. 命令行参数
1.1 读取参数
bash shell会将一些称为位置参数(positional parameter)的特殊变量分配给输入到命令行中的所有参数(包括shell所执行的脚本名称)。
位置参数变量是标准的数字:
$0
是程序名,
$1
是第一个参数,通常依次到
$9
。
eg:
a=1
for((num=1;num<$1;num++))
do
a=$[ $a+$num ]
done
echo $a
#11
notice:
- 需要输入更多的命令行参数,则每个参数都必须用空格分开。
- shell脚本会自动将命令行参数的值分配给变量,不需要作任何处理。
- 当遇到传入参数带有空格时,记得用引号包括起来(单双引号都可)。
- 当命令行参数超过9个时候,第10个参数以及第10+n个参数的引用需要使用花括号。如
${10}
1.2 读取脚本名– $0
$0
以用$0参数获取shell在命令行启动的脚本名。
读取脚本名有如下需要注意的:
- 如果使用另一个命令来运行shell脚本,命令会和脚本名混在一起,出现在$0参数中。
- 当传给$0变量的实际字符串不仅仅是脚本名,而是完整的脚本路径时,变量$0就会使用整个路径。
Q:如何避免上述问题?
A:使用
basename
命令即可。
eg:
echo $0
path=$(basename $0)
echo $path
#/home/hogoadr/workspace/share/george/shell/myshell
#myshell
1.3 测试参数– -n
-n
当脚本认为参数变量中会有数据而实际上并没有时,脚本很有可能会产生错误消息。
在使用参数前一定要检查其中是否存在数据。
可以使用**-n**测试来检查命令行参数$1中是否有数据。
eg:
if [ -n "$1" ] #使用 -n 测试 是否执行使用参数1的相关代码块
then
a=1
for((num=1;num<$1;num++))
do
a=$[ $a+$num ]
done
echo $a
else
echo "no parameter 1 "
fi
#no parameter 1
2.特殊参数变量
2.1 参数统计– $#
$#
特殊变量$#含有脚本运行时携带的命令行参数的个数。可以在脚本中任何地方使用这个特殊变量,就跟普通变量一样。这样就可以避免多个参数需要一个一个测试的繁琐。
eg:
if [ $# -eq 2 ];then
echo "parameter is 2"
elif [ $# -eq 1 ];then
if [ -n "$1" ];then
a=1
for((num=1;num<$1;num++))
do
a=$[ $a+$num ]
done
echo $a
fi
else
echo "no parameter 1 "
fi
#根据携带参数走不同分支
notice:
- if-then语句用**-ne**测试命令行参数数量。如果参数数量不对,会显示一条错误消息告知脚本的正确用法。
-
用来获取命令行中最后一个参数。${!#}
- 当命令行上没有任何参数时,
的值为0,params变量的值也一样,但${!#}变量会返回命令行用到的脚本名。$#
2.2 抓取所有数据– $*
和 [email protected]
[遍历命令行的绝妙方法]
$*
[email protected]
命令 | 描述 | 异 | 同 |
---|---|---|---|
$* | 用来轻松访问所有的参数 | 1.将命令行上提供的所有参数 当作一个单词保存 2.基本上$*变量会将这些参数视为一个整体 而不是多个个体 | 能够在单个变量中存储所有的命令行参数 |
[email protected] | 用来轻松访问所有的参数 | 将命令行上提供的所有参数当作同一字符串中的多个独立的单词,通常使用for命令遍历得到每个参数值 |
eg:
cnt=1
for para in $"$*"
do
echo "\$* $cnt = $para"
cnt=$[ $cnt + 1 ]
done
cnt=1
for para in $"[email protected]"
do
echo "\[email protected] $cnt = $para"
cnt=$[ $cnt + 1 ]
done
#$* 1 = 5:8:6:9:7
#[email protected] 1 = 5
#[email protected] 2 = 8
#[email protected] 3 = 6
#[email protected] 4 = 9
#[email protected] 5 = 7
3.移动变量–shift命令[遍历命令行参数的另一个好方法]
shift命令会根据它们的相对位置来移动命令行参数。(遍历命令行参数的另一个好方法,在不知道有多少个命令行参数的时候,只读第一个参数)
notice:
- 在使用shift命令时,默认情况下它会将每个参数变量向左移动一个位置。
- 使用shift命令的时候要小心。如果某个参数被移出,它的值就被丢弃了,无法再恢复。
- 可以一次性移动多个位置,即给shift 命令后面跟个n个位置参数,指明要移动的位置数。
- 通过使用shift命令的参数,可以轻松的跳过不需要的参数。
eg:
echo
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1" #不知道实际参数个数,只取第一个参数
count=$[ $count + 1 ]
shift
done
#Parameter #1 = 5
#Parameter #2 = 8
#Parameter #3 = 6
#Parameter #4 = 9
#Parameter #5 = 7
4.处理选项
4.1 查找选项
bash shell 脚本可以像处理命令行参数一样处理命令行选项。
处理命令行选项需要注意如下两点:
- 分离参数和选项;
- 处理带值的选项。
Q:如何分离参数和选项?
A:Linux使用标准方法是使用特殊字符。双破折线(–),shell会用双破折现线来表明选项列表的结束。
ps:处理带值的选项通常包括注意选项的合并。eg:
ls -la
4.2 使用getopt命令-格式化命令行选项和参数
getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格式,是一个在处理命令行选项和参数时非常方便的工具。
其格式如下:
getopt optstring parameters
optstring是这个过程的关键所在。
它定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值。
其流程如下:
首先,在optstring中列出你要在脚本中用到的每个命令行选项字母。
然后,在每个需要参数值的选项字母后加一个冒号。
getopt命令会基于你定义的optstring解析提供的参数。
eg:
$ getopt ab:cd -a -b test1 -cd test2 test3
-a -b test1 -c -d -- test2 test3
ps: getopt -q 选项可以忽略错误信息(若指定了一个不在optstring中的选项)
Q:如何在脚本中使用getopt命令?
A:方法是用getopt命令生成的格式化后的版本来替换已有的命令行选项和参数。用set命令能够做到。
set命令的选项之一是双破折线(–),它会将命令行参数替换成set命令的命令行值。
该方法会将原始脚本的命令行参数传给getopt命令,之后再将getopt命令的输出传给set命令,用getopt格式化后的命令行参数来替换原始的命令行参数。
其格式如下:
现在原始的命令行参数的值会被getopt命令的输出替换,而getopt命令以及将原始命令行参数进行了格式化。
notice:
getopt命令并不擅长处理带空格和引号的参数值。它会将空格当作参数分隔符,而不是根据双引号将二者当作一个参数。
4.3 使用更高级的getopts–避开getopt命令的劣势扩展了一些功能
getopts命令(注意是复数)是bash shell的内建。相比getopt命令多了一些扩展功能并且避开了getopt命令不擅长处理带空格和引号的参数值。
命令 | 区别 |
---|---|
getopt | 1.将命令行上选项和参数处理后只生成一个输出 |
getopts | 1.能够和已有的shell参数变量配合默契 2.一次只处理命令行上检测到的一个参数 3.处理完所有参数后,退出并返回一个大于0的退出状态码 4.可以在参数值中包含空格 5.可以将选项字母和参数值放在一起使用而不用加空格 6.能够将命令行上未定义的选项统一输出成问号 |
getopts命令格式如下:
getopts optstring variable
notice:
- optstring同样和getopt一样也是关键;
- 有效的选项字母都会列在optstring中,如果选项字母要求有参数值,就加一个冒号;
- 要去掉错误消息,可以在optstring之前加一个冒号,这和getopt命令显得不同;
- getopts命令将当前参数保存在variable中;
- getops命令解析命令行选项时会移除开头的单破折线。
ps:
1.getopts命令会用到两个环境变量。(OPTARG和OPTIND)
OPTARG环境变量会保存选项需要跟的参数值;
OPTIND环境变量保存了参数列表中getopts命令正在处理的参数位置。(getopts命令在处理每个选项时,OPTIND的值会增一)
5.将选项标准化
6.获得用户输入– read
read
6.1 基本的获取
read命令从标准输入(键盘)或另一个文件描述符中接收输入。
ps:
- echo -n 选项 不会在字符串末尾输出换行符。
- read命令使用-p选项,允许直接在read命令行指定提示符。(若使用了-p选项而没有指定提示符,则会出乎所料哦)。
- read命令会将提示符输入的所有数据分配给单个变量(若变量数量不够,剩下的数据就全部分配给最后一个变量,因此要么指定多个变量,要么全部分配给最后一个变量)。
- 若read命令行中没有指定变量,则read命令会将它收到的任何数据都放进特殊环境变量REPLY中。
eg:
read -p name
echo $name
read name
echo $name
read -p "Please input you namef: " namef
echo $namef
read -p "Please input you namef: " names
echo $names
read
echo $REPLY
#namewang heng
#
#wang heng
#wang heng
#Please input you namef: wang
#wang
#Please input you namef: heng
#heng
#who
#who
6.2 超时–read需要超时判断
Q:如何做到read超时判断?
A:有如下两种办法:
- read -t 计时判断。-t选项指定一个计时器,指定了read命令等待输入的秒数,当计时器过期后,read命令会返回一个非零的退出状态码。
- 也可以让read命令来统计输入的字符数(-n)。当输入的字符达到预设的字符数时,则自动退出,将输入赋值给变量。
eg:
#read -t
if read -t 5 -p "Please input a num: " num;then
echo "the num is $num"
else
echo "is too slow"
fi
#read -n
read -n1 -p "Continue?[Y/N]" answer #将-n选项和值1一起使用,告诉read命令在接受单个字符后退出
case $answer in
Y | y) echo "continue..";;
N | n) echo
echo "not continue.."
exit;;
esac
echo "shell is over.."
#Please input a num: 2
#the num is 2
#Continue?[Y/N]n
#not continue..
#Please input a num: is too slow
#Continue?[Y/N]ycontinue..
#shell is over..
6.3 隐藏方式读取– -s
典型应用于密码输入上
-s
-s选项可以避免在read命令中输入的数据出现在显示器上(实际上,数据会被显示,只是read命令会将文本颜色设成跟背景色一样)
eg:
#read -s
if read -t 5 -s -p "Please input the passwd: " pswd;then
echo "the pswd is $pswd"
else
echo "is too slow"
fi
#Please input the passwd: the pswd is 123
6.4 从文件读取
每次调用read命令,它都会从文件中读取一行文本。
当文件中再没有内容时,read命令会退出并返回非零退出状态码。
Q:如何将文件内容传输给read命令?
A:最常见的方法是对文件使用cat命令,将结果通过管道直接传给含有read命令的while命令。
eg:
cnt=1
cat 3_1_while.log | while read line
do
echo "read line$cnt is $line"
cnt=$[ $cnt + 1 ]
done
#read line1 is 5
#read line2 is 4
#read line3 is 3
#read line4 is 2
#read line5 is 1
申明:文中没特殊注明,图皆来自Linux命令行与shell脚本编程大全<第三版>。