天天看点

【读书笔记】Linux命令行与Shell脚本编程大全--处理用户输入1. 命令行参数2.特殊参数变量3.移动变量–shift命令[遍历命令行参数的另一个好方法]4.处理选项5.将选项标准化6.获得用户输入–read

文章目录

  • 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:

  1. 需要输入更多的命令行参数,则每个参数都必须用空格分开。
  2. shell脚本会自动将命令行参数的值分配给变量,不需要作任何处理。
  3. 当遇到传入参数带有空格时,记得用引号包括起来(单双引号都可)。
  4. 当命令行参数超过9个时候,第10个参数以及第10+n个参数的引用需要使用花括号。如

    ${10}

1.2 读取脚本名–

$0

以用$0参数获取shell在命令行启动的脚本名。

读取脚本名有如下需要注意的:

  1. 如果使用另一个命令来运行shell脚本,命令会和脚本名混在一起,出现在$0参数中。
  2. 当传给$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**测试来检查命令行参数$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:

  1. if-then语句用**-ne**测试命令行参数数量。如果参数数量不对,会显示一条错误消息告知脚本的正确用法。
  2. ${!#}

    用来获取命令行中最后一个参数。
  3. 当命令行上没有任何参数时,

    $#

    的值为0,params变量的值也一样,但${!#}变量会返回命令行用到的脚本名。

2.2 抓取所有数据–

$*

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

  1. 在使用shift命令时,默认情况下它会将每个参数变量向左移动一个位置。
  2. 使用shift命令的时候要小心。如果某个参数被移出,它的值就被丢弃了,无法再恢复。
  3. 可以一次性移动多个位置,即给shift 命令后面跟个n个位置参数,指明要移动的位置数。
  4. 通过使用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 脚本可以像处理命令行参数一样处理命令行选项。

处理命令行选项需要注意如下两点:

  1. 分离参数和选项;
  2. 处理带值的选项。

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:

  1. optstring同样和getopt一样也是关键;
  2. 有效的选项字母都会列在optstring中,如果选项字母要求有参数值,就加一个冒号;
  3. 要去掉错误消息,可以在optstring之前加一个冒号,这和getopt命令显得不同;
  4. getopts命令将当前参数保存在variable中;
  5. getops命令解析命令行选项时会移除开头的单破折线。

ps:

1.getopts命令会用到两个环境变量。(OPTARG和OPTIND)

OPTARG环境变量会保存选项需要跟的参数值;

OPTIND环境变量保存了参数列表中getopts命令正在处理的参数位置。(getopts命令在处理每个选项时,OPTIND的值会增一)

5.将选项标准化

【读书笔记】Linux命令行与Shell脚本编程大全--处理用户输入1. 命令行参数2.特殊参数变量3.移动变量–shift命令[遍历命令行参数的另一个好方法]4.处理选项5.将选项标准化6.获得用户输入–read

6.获得用户输入–

read

6.1 基本的获取

read命令从标准输入(键盘)或另一个文件描述符中接收输入。

ps:

  1. echo -n 选项 不会在字符串末尾输出换行符。
  2. read命令使用-p选项,允许直接在read命令行指定提示符。(若使用了-p选项而没有指定提示符,则会出乎所料哦)。
  3. read命令会将提示符输入的所有数据分配给单个变量(若变量数量不够,剩下的数据就全部分配给最后一个变量,因此要么指定多个变量,要么全部分配给最后一个变量)。
  4. 若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:有如下两种办法:

  1. read -t 计时判断。-t选项指定一个计时器,指定了read命令等待输入的秒数,当计时器过期后,read命令会返回一个非零的退出状态码。
  2. 也可以让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选项可以避免在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脚本编程大全<第三版>。

继续阅读