Linux学习--No.11 设置脚本参数、选项
之前使用生信软件时,会加好多选项参数。这次简单学习下在自己的脚本中,添加选项及参数。最后再学习一个获得用户输入的常用命令
read
要点一、命令行参数
1、基础用法--位置参数变量
bash shell 给输入到命令行的所有参数,定义了位置参数(positional parameter)的特殊变量,形式为标准的数字,举一例就明白了。
./test.sh 10 20
- $0 一般是脚本名
./test.sh
- $1 是第一个参数
10
- $2 是第二个参数
20
以此类推,直到第9个参数 $9,用户可以在命令行赋值给相应的变量。如上述将数值10、20分别赋值给脚本test.sh中的$1、$2位置参数变量,从而可以在脚本中使用这些变量。如下是一个简单的例子
cat test1.sh
#!/bin/bash
#
total=$[ $1*$2 ]
echo The first parameter is $1
echo The second parameter is $2
echo total value is $total
./test1.sh 3 9
除了上述用数字赋值给位置参数变量外,也可以用文本字符串赋值。如果含空格,加上引号(单双均可)
2、特殊的位置参数变量
2.1、 $0
$0 参数,一般就是指脚本名。但是如果用全路径(绝对/相对)执行脚本时,$0同样会含有路径名。此时可以用basename
命令进行简化。
cat test2.sh
#!/bin/bash
#
cat test2.sh
echo the first name is $0
echo the new name is $(basename $0) #命令替换
./test3.sh
- 注意观察输出的两处不同,
basename
命令可以打印目录或者文件(如脚本)的基本名称。
2.2、 多于9个变量
当然也可以输入不止9个变量,不过在脚本引用第9个以后的参数时,要加上花括号 。比如${11}
即表示第11个位置参数,而不能简单使用$11
。(只是理论上有这种用法,一般都用不到这么多参数吧)
3、遍历位置参数变量
3.1、储存所有参数方法
-
$@
变量默认储存了在命令行输入的所有参数,从而可在脚本中搭配for语句,遍历所有位置参数变量
cat test3.sh
#!/bin/bash
#
echo
#
count=1
for param in "$@"
do
echo "\$@ Parameter #$count = $param" #注意转义符的使用。
count=$[ $count + 1 ]
done
./test3.sh jim tom sam
#该脚本会逐一迭代"$@"里的参数值,用于执行循环命令
与之类似的变量是
$*
,但是$*
是把所有输入的参数当做一个整体使用(一个含空格的字符串可能更好理解)。
此外还有一个挺有用的变量$#
,它能统计命令行输入了多少个参数。这常用于提醒用户输入正确数目的参数。
3.2、不断前移变量法
-
shift
命令可以将每个参数变量都向前移动一个位置,比如$2的值移动到$1,$3的值移动到$2,......而原先$1的值会被删除($0不受影响)。如此不断使用shift
命令也可以实现遍历所有位置参数变量。(我觉得这种方法可能更常用)
cat test4.sh
#!/bin/bash
#
echo
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
count=$[ $count + 1 ]
shift
done
- 因为每次循环都会前移一个变量,所以脚本中只要考虑
$1
位置参数变量即可。 -
[ -n "$1" ]
的-n用于判断$1的字符串长度是否大于0,作为whlie语句的执行依据。
./test4.sh jim tom sam
#效果同前法
要点二、命令行选项
- 书写格式:单破折号后面跟一个字母,比如
-a
- 如果说命令行参数能够提供数据的话,那么命令行选项则能改变命令的行为。即一个选项对应一种特色的功能。可以联想我们之前学习Linux命令时所接触的一些选项,比如
ls -l
。 - 一般来说分为有效选项与无效选项,后者即为未定义选项。因此脚本命令要有区分的能力,常搭配case语句。case语句会检查每个参数是不是有效选项,是的话,就运行对应case语句中的命令。
在下面的一些例子中,仅举了十分简单的输出命令。不过记住选项的功能是很强大的。
1、常规处理方法
cat test5.sh
#!/bin/bash
#
echo
while [ -n "$1" ]
do
case "$1" in #case用法,确认参数属于下列哪四种情况之一
-a) echo "Found the -a option" ;; # 双分号也是固定格式
-b) echo "Found the -b option" ;;
-c) echo "Found the -c option" ;;
-*) echo "$1 is not an option" ;;
esac #标志结束(case 倒过来了)
shift #前移参数
done
- 结合上例,学习下case语句的用法;
- 搭配
shift
命令,遍历所有选项。 -
-*)
处代码设置了非以上三种有效选项情况下的报错语句。
./test5.sh -a -cb -e
- 选项合并书写也是一种很常见的,友好的写法。
特殊情况1、识别命令行中同时输入的选项与参数
- 办法:在选项与参数间使用双破折线。
- 当脚本遇到双破折线时,停止处理选项,并将剩下的参数都当做命令行参数(其实并非这么“智能”,需要在脚本代码中予以交代的)。
cat test6.sh
#!/bin/bash
#
echo
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 "$1 is not an option" ;;
esac
shift #前移参数
done
#处理完选项,再处理参数~
count=1
for param in $@
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
./test9.sh -a -cb -- 5 9 6 3
特殊情况2、处理带值(参数)的选项
cat test7.sh
#!/bin/bash
#
echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2"
echo "Found the -b option, with parameter value $param" ;;
shift ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
-*) echo "$1 is not an option" ;;
esac
shift
done
#
count=1
for param in $@
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
- 这里
-b
选项需要有一个参数,命令行书写要注意。 - 因为
-b
选项加上连带参数占据两个位置,要前移两次参数。
./test7.sh -c -b 5 -d -a
2、getopt命令读取选项、参数
-
getopt
命令可以接受一系列任意形式的命令行的选项和参数,并自动将它们转换成适当的格式。 - 用法:
getopt optstring parameters
,其中optstring
定义了命令行有效的选项字母;如果为需要参数数据的选项,则在字母后面加一个冒号。如果命令行输入了不属于定义范围的无效选项,会返回报错信息。parameters
为用户输入的选项参数。
cat test8.sh
#!/bin/bash
#
set -- $(getopt -q ab:cd "$@")
echo
while [ -n "$1" ]
do
case "$1" in
#以下代码与前相同,不赘述
-
ab:cd
表getopt识别 -a、-c、-d选项,以及带有参数的-b选项;以及后面的数据参数; -
set --
将getopt命令生成的格式化后的版本来替换已有的命令行选项和参数(排除掉无效参数); -
getopt
的-p
参数能够忽略无效选项的报错信息。
可能会觉得与上一个脚本没什么区别,唯一的不同就是加入了getopt命令来帮助格式化命令行参数。优势的话就是提前筛选了有效选项,并且不用加
--
来把选项与参数分开了。(那么脚本里的相应代码可以省略吗?因为无法演示,存疑!)
3、getopts命令读取选项、参数
getopts
为getopt
的高级版。主要区别为getopt
将命令行上的选项和参数处理后一次性全部输出;getopts
则是一次只处理命令行上检测到的一个选项。
- 用法:
getopts optstring variable
optstring
值同前,variable
为储存迭代用户输入的选项的变量名。若发现未定义的选项,会输出成?
问号。并且getopts
知道何时停止处理选项,并将参数留给用户处理。见下面的例子就好理解了
cat test9.sh
#!/bin/bash
#
echo
while getopts : ab:cd opt
do
case "$opt" in
a) echo "Found the -a option" ;; #注意这里的选项书写,不用加破折号
b) echo "Found the -b option, witn value $OPTARG" ;;
c) echo "Found the -c option" ;;
*) echo "Unknown option: $opt" ;;
esac
done
#
shift $[ $OPTIND - 1 ]
#
echo
count=1
for param in "$@"
do
echo "Parameter $count: $param"
count=$[ $count + 1 ]
done
上述代码涉及到关于getopts
的两个重要环境变量
- OPTARG变量会在选项带有参数数据时,保存该参数值;见上
-b
选项处理参数的用法。 - OPTIND变量保存了参数列表中
getopts
正在处理的参数位置;见上,配合shift
开始处理参数时的用法。
./test9.sh -ab test1 -c 10 15 95
综上就是关于脚本从参数、选项获得输入的学习,最后再学习另一个常用的读取命令
read
。
read
命令从键盘输入或一个文件中接受输入;在收到输入后,read命令会将数据放进一个变量(名字自己随便取),以供使用.
(1)键盘输入--实现交互式操作
#!/bin/bash
#
echo -n "Enter your name: "
read name #将变量命名为name
echo "Hello $name, welcome to my home"
上述代码实现了接受键盘输入的数据,将其存到变量 name,然后使用变量。此用法还可配合 -p ,-t(超时),-s(隐藏读取) 选项使用(详见p306)
(2)文本文件读取
- 前期准备文本文件
cat test.txt
how are you
i am fine
that is great
- read读取
#!/bin/bash
#
count=1
cat test.txt | while read line
#cat的结果通过管道符传给含有read命令(逐行读取)的while命令
do
echo "Line $count: $line"
count=$[ $count + 1 ]
done
循环会持续通过read命令处理文件中的行,直到read命令以非零退出状态码退出。
以上就是处理用户输入的脚本参数