fsx2550553488的博客

说什么好呢

shell脚本用户输入处理——shell编程学习_七

用户输入处理

在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命令

getoptsgetopt的升级版本,使用方法大不相同

示例:

[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"


阅读更多
个人分类: RH Linux
上一篇shell编程中的循环——shell编程学习_六
下一篇Linux中的信号——shell编程学习_八
想对作者说点什么? 我来说一句

shell输入与输出

2010年06月28日 405KB 下载

没有更多推荐了,返回首页

关闭
关闭