在Linux操作系统中,用户输入一般分为两类:
命令行参数
这是在命令启动时将数据传递,命令行参数形式一般包括:命令、选项、参数
选项用来定义用户的行为
参数用来向命令传递特定的数据
如:
[root@shell input]# ls -a test_1.sh test_1.sh //即瞬间生成进程,执行完瞬间释放。参数的传递应该和命令的进行同时
运行时输入
这种是在命令启动之后,将数据传递。
如:
[root@shell input]# cat test_1.sh test_1.sh fsx fsx //即先生成命令进程,然后在传入数据,进行处理。
命令行参数的使用
读取参数
参数之间使用空格进行分割
在脚本中,使用位置参数的特殊变量,来进行参数读取:$+position。
如:$0
$1
$2
.......
其中,$0表示的是程序名
真正的参数是从$1开始的
到了第十个参数,就需要${10}这样的形式来表示了。
示例:
[root@shell input]# cat test_1.sh #!/bin/bash echo "the #1 param is: $1" //这里第一个参数必须是$1、否则内核不识别 echo "the #2 param is: $2" SUM=$[ $1+$2] echo "the restult is $SUM" [root@shell input]# bash test_1.sh 2 3 the #1 param is: 2 the #2 param is: 3 the restult is 5
如果要用第一个参数和第五个参数,就要:
[root@shell input]# cat test_2.sh //具体代码 #!/bin/bash echo "the #1 param is: $5" echo "the #2 param is: $1" SUM=$[ $1+$5] echo "the restult is $SUM" [root@shell input]# bash test_2.sh 2 3 //这里只串进来了两个参数,所以无法识别到第五个参数 the #5 param is: the #1 param is: 2 test_2.sh: line 6: 2+: syntax error: operand expected (error token is "+") the restult is [root@shell input]# bash test_2.sh 2 3 1 2 5 //这里串进来了五个参数,第五个参数值为5,所以输出的是2+5 the #5 param is: 5 the #2 param is: 2 the restult is 7
$0是我们输入的第一个参数,即文件名(包含路径)
[root@shell mnt]# cat input/test_3.sh #!/bin/bash echo "the bash file name $0" echo "the #1 param is: $3" echo "the #2 param is: $2" echo "the #2 param is: $1" SUM=$[ $1+$2 ] echo "the restult $1+$2 is $SUM" [root@shell mnt]# pwd /mnt [root@shell mnt]# bash input/test_3.sh 1 2 3 the bash file name input/test_3.sh the #1 param is: 3 the #2 param is: 2 the #2 param is: 1 the restult 1+2 is 3
有时候我们只想获取命令(文件名),我们就需要引入basename
关键字
[root@shell mnt]# cat input/test_3.sh #!/bin/bash echo "the bash file name ` basename $0`" echo "the #1 param is: $3" echo "the #2 param is: $2" echo "the #2 param is: $1" SUM=$[ $1+$2 ] echo "the restult $1+$2 is $SUM" [root@shell mnt]# bash input/test_3.sh 1 2 3 the bash file name test_3.sh //有了`basename`关键字,这是的name值是命令(文件名)名字 the #1 param is: 3 the #2 param is: 2 the #2 param is: 1 the restult 1+2 is 3 [root@shell mnt]# pwd /mnt 这是一个很有意义的关键字
使用basename
的一个好处:可以在一个shlle脚本中,实现多种命令,用软连接对脚本重命名,调用不同的软连接实现不同功能。
示例:编辑shell脚本,test_4.sh
[root@shell input]# cat test_4.sh #!/bin/bash name=`basename $0` if [ $name = "add" ] //当命令(执行的脚本名)名字为 add 时,执行 if 语句里面的命令,即加法 then result=$[ $1+$2 ] elif [ $name = "minus" ] //当命令(执行的脚本名字)名字为 minus 时,执行 elif 语句里面的命令,即减法 then result=$[ $1-$2 ] fi echo "the $name result is $result"
然后制作两个软连接,分别指向test_4.sh,一个命名为add
,一个命名为minus
,分别执行
[root@shell input]#ln -s test_4.sh add [root@shell input]#ln -s test_4.sh minus [root@shell input]# ./add 4 5 //使用add时,加法 the add result is 9 [root@shell input]# ./minus 4 5 //使用minus时,减法 the minus result is -1 [root@shell input]# ll //==ls -l total 16 lrwxrwxrwx 1 root root 9 Apr 16 08:12 add -> test_4.sh lrwxrwxrwx 1 root root 9 Apr 16 08:12 minus -> test_4.sh -rw-r--r-- 1 root root 177 Apr 16 07:26 test_3.sh //通过一个脚本实现两个命令
几个特殊的变量
Linux规定了一些默认的变量,如:
$#:参数计数
$*:所有参数
$@:参数列表
示例:
[root@shell input]# bash test_5.sh 1 2 3 4 a 5 //$# 1 2 3 4 a //$@ 1 2 3 4 a //$* [root@shell input]# cat test_5.sh #!/bin/bash echo $# echo $@ echo $* //$@和$*在这里有什么区别呢?
示例2:
[root@shell input]# bash test_6.sh 1 2 3 4 a 5 1 2 3 4 a 1 2 3 4 a $* param = 1 2 3 4 a //$*把所有参数当成一个字符串来处理,存在的是一个变量 $@ param = 1 //$@吧参数当成以一个列表 $@ param = 2 $@ param = 3 $@ param = 4 $@ param = a [root@shell input]# cat test_6.sh //具体代码 #!/bin/bash echo $# echo $@ echo $* for var in "$*" do echo "\$* param = $var" done for var in "$@" do echo "\$@ param = $var" done
命令行参数的处理
条件判断
用户的输入是千奇百怪的,为了避免用户输入不匹配,并且给用户更好的体验,使用判断对命令行参数进行基本的验证是很有必要的。
使用条件判断对参数个数进行规定,如果不是条天判断中的个数,则直接返回错误,结束程序。
[root@shell input]# bash test_7.sh 2 //当只有一个参数的时候,输出判断结果 input error [root@shell input]# cat test_7.sh #!/bin/bash if [ $# -lt 2 ] //对参数的基本验证,本shell脚本要求是两个参数 then echo "input error" exit fi echo "the #1 param is: $2" echo "the #2 param is: $1" SUM=$[ $1+$2] echo "the restult is $SUM"
shift
命令:用来移动参数,来进行多参数处理。不断向前移动位置参数。
[root@shell read]# cat sum.sh #!/bin/bash result=0 while [ -n "$1" ] do result=$[ $result + $1 ] shift //shift每次将所有参数向前移动一次,原本的$1就被丢弃,$2变成$1......达到使用一个$1就遍历所有的参数 done echo "total number is: $result" [root@shell read]# bash sum.sh 123 45 1 4325 total number is: 4494
shift
类似于主动遍历所有参数,将每个参数都当成$1
执行一次。
进行命令行选项处理
在Linux中,选项是一种对命令行为进行设置的通用方式。通常是-字母
处理简单选项
这样很适合linux中的agent,(start|restart|stop|reload)
[root@shell read]# cat test_6.sh #!/bin/bash while [ -n "$1" ] do case "$1" in -a) echo "使用选项 -a";; -b) echo "使用选项 -b";; -v) echo "使用选项 -v";; esac shift done [root@shell read]# bash test_6.sh -v 使用选项 -v [root@shell read]# bash test_6.sh -a 使用选项 -a
参数和选项进行隔离
使用--
对参数和选项进行分离,具体实现:
[root@shell read]# cat test_7.sh #!/bin/bash while [ -n "$1" ] do case "$1" in -a) echo "input -a";; -b) echo "input -b";; -v) echo "input -v";; --) shift //当遇到--前,一致遍历$1,一遇到`--`跳出while循环 break;; esac shift //跳出循环后,继续shift遍历 done echo "input other is $*" //输出其他的参数
执行结果:
[root@shell read]# bash test_7.sh -a -v -- fsx 123 input -a input -v input other is fsx 123
处理带值的选项
通常,我们会在选项后面加入一些值,实现示例:
[root@shell read]# cat test_8.sh #!/bin/bash while [ -n "$1" ] do case "$1" in -a) echo "input -a";; -b) value="$2" //匹配到-b后,定义一个$2变量保存下一个参数 echo "input -b,result is $value" //然后输出$2 shift;; //因为这$1下一个参数被$2拿走,shift要向前走一次,才能完成后续遍历 -v) echo "input -v";; --) shift break;; esac shift done echo "input other is $*"
参数合并问题
实际情况中,我们还会遇到选项合并的情况,如:-av
这时候使用getopt
命令来实现
[root@shell read]# getopt abcd -b -acd //abcd是一个passing的语句,指定能够解析哪些选项,这里就是说明可以解析a、b、c、d -b -a -c -d -- //
--
是结束的标志[root@shell read]# getopt abcd -bacd -b -a -c -d --
[root@shell read]# getopt ab:cd -b fsx -acd qpy hh //某一个选项后面有冒号,表示这个选项后面可以带值。 -b fsx -a -c -d -- qpy hh //这里进行了正确的匹配,字符串
fsx
属于-b
的值
脚本实现示例:
[root@shell read]# cat test_9.sh #!/bin/bash set -- `getopt -q ab:v "$@"` //使用set -- 将getopt的结果赋给命令行参数,之后就可以继续使用位置参数来访问已经解析后的变量。-q是--quit的意思,指不会输出getopt遇到的错误。$@原来命令行参数的集合 while [ -n "$1" ] do case "$1" in -a) echo "input -a";; -b) value="$2" echo "input -b,result is $value" shift;; -v) echo "input -v";; --) shift break;; esac shift done echo "input other is $*"
测试:
[root@shell read]# bash test_9.sh -b fsx -av -- qpy hh //这里-av可以放在以其,解析时分开 input -b,result is 'fsx' input -a input -v input other is 'qpy' 'hh' //如果-b后面的值包含空格怎么办?使用双引号不管用,如: [root@shell read]# bash test_9.sh -b "fsx qpy" -av -- qpy hh input -b,result is 'fsx //并没有正确解析值,getopt不能解析空格值,这时需要使用getopts命令 input -a input -v input other is 'qpy' 'hh'
参数合并问题二
getopt不能解析有空格的值,这时需要使用getopts命令
getopts
是getopt
的升级版本,使用方法大不相同
示例:
[root@shell read]# cat getopts.sh #!/bin/bash while getopts ab:v opt #直接通过getopts获取,ab:v和getopt一样,把解析出来的选项赋值给opt变量 do case "$opt" in a) echo "input -a";; b) echo "input -b,result is $OPTARG";; #OPTARG是一个全局环境变量,是选项参数的意思。可以访问选项参数值 v) echo "input -v";; *) echo "unknow options $opt";; #getopts不需要"--" esac done shift $[ $OPTIND +1 ] #OPTIND是解析的选项个数,也是一个全局环境变量。这里跳到所有参数结束,去访问getopts结束作用后,后面的参数 count=1 //打印每输入的每一行参数 for param in "$@" do echo "param #$count is : $param" count=$[ $count + 1] done
执行测试:
[root@shell read]# bash getopts.sh -av -b "fsx 123" qpy input -a input -v input -b,result is fsx 123 param #1 is : -av param #2 is : -b param #3 is : fsx 123 param #4 is : qpy
在shell中,规定了一些通用的选项含义,依次来进行一些相通的命令的操作
选项 | 含义 |
---|---|
-a | 显示所有对象 |
-c | 生成一个计数 |
-d | 指定一个目录 |
-e | 扩展一个对象 |
-f | 指定读取数据的文件 |
-h | 显示命令的帮助信息 |
在脚本运行时获取输入
在脚本中获取输入,可以使用read
命令
read
的基本读取
示例:
[root@shell read]# bash test_1.sh type your input fsx you type fsx [root@shell read]# cat test_1.sh #!/bin/bash echo "type your input" read input //从标准输入中读取一个参数,并且保存到变量input中 echo "you type $input"
read
的处理超时
示例:
这里使用read
的-t
参数,指定超时时间
[root@shell read]# cat test_2.sh #!/bin/bash if read -t 2 -p "type your input " input //如果超时两秒钟没有输入,则执行else中的命令 then echo "you type $input" else echo " timeout" fi
执行结果:
[root@shell read]# bash test_2.sh //如果2秒中内,没有输入,则输出timeout type your input timeout [root@shell read]# bash test_2.sh //2秒内输入,则执行if中的语句 type your input fsx you type fsx
不回显的read
读取
示例:
这里使用read
的-s
参数,设置输入不回显
[root@shell read]# bash test_3.sh type your input you type fsx123 [root@shell read]# cat test_3.sh #!/bin/bash echo "type your input" read -s passwd //-s指定,用户在终端输入数据,不回显,保存到passwd变量中 echo "you type $passwd" //执行输出
从文件中读取输入
read
也接收从文件的输入,可以使用文件重定向,或者管道的方式
使用文件重定向的方式
示例:
[root@shell read]# cat test_4.sh #!/bin/bash exec 0< test_1.sh //重定向,将输入重定向到test_1.sh count=1 //记录行数 while read line //line是变量名 do echo "#$count: $line" //输出行数,和文件该行的内容 count=$[ $count + 1 ] done [root@shell read]# ls test_1.sh test_2.sh test_3.sh test_4.sh [root@shell read]# bash test_4.sh //执行结果 #1: #!/bin/bash #2: #3: echo "type your input" #4: read input #5: echo "you type $input"
使用管道的方式:
示例:
[root@shell read]# cat test_5.sh #!/bin/bash read filename //保存变量,终端读取参数 count=1 //记录行数 cat $filename | while read line //将输入的参数通过管道传递给while语句,用line来保存 do echo "#$count: $line" count=$[ $count + 1 ] done [root@shell read]# bash test_5.sh test_1.sh //键入参数 #1: #!/bin/bash #2: #3: echo "type your input" #4: read input #5: echo "you type $input"