1. 命令行参数
1.1. 传递命令行参数
向shell脚本传递数据的最基本方法是使用命令行参数。命令行参数允许在运行脚本时向命令
行添加数据。比如这样sh hello.sh 10 20
1.2. 位置参数
bash shell 会将一些称为位置参数(positional parameter)的特殊变量分配给输入到命令行中的所有参数。
$0
是程序名,$1
是第一个参数,$2
是第二个参数,依次类推,直到第九个参数$9
。当然最多并不仅仅支持 9 个参数,如果需要支持多余 9 个的位置参数需要稍微修改一下变量名。在第9个变量之后,编写程序引用位置参数时你必须在变量数字周围加上花括号,不然 shell 会将他们识别成两个参数,比如${10}
,参数位置参数支持普通的数值,同时也支持例如字符串等其他类型的参数。
这是一个使用位置参数的例子,可以在文件名后跟随一个位置参数来进行参数赋值,程序中可以使用位置参数进行引用。
a=1
for (( number = 1; number <= $1; number++ ))
do
a=$[$a * $number]
done
echo The a of $1 is $a
1.3. 读取脚本名
我们可以用
$0
参数来获取 shell 在命令行中执行的脚本的脚本名。这个在我们需要读取我们脚本名时是很方便的。
使用
$0
来读取脚本名称存在的问题:
如果使用另一个命令来运行shell脚本,命令会和脚本名混在一起,出现在$0
参数中。
当传给$0
变量的实际字符串不仅仅是脚本名,而是完整的脚本路径时,变量$0
就会使用整个路径。使用时你需要把脚本的运行路径给剥离掉。另外,还要删除与脚本名混杂在一起的命令。
解决使用
$0
来读取脚本名称存在的问题:
使用basename
命令,命令会返回不包含路径的脚本名。比如file_name=$(basename $0)
1.4. 测试参数
shell 脚本中使用命令行参数时要小心些。如果脚本不加参数运行,将会会出现问题。所以在使用参数前必须要检查其中是否存在参数。
2. 特殊参数变量
bash shell 中含有一些特殊变量,它们会记录命令行参数的数量。
2.1. 参数统计
特殊变量
$#
中记录着脚本输入参数的总数,可以在脚本中任何地方使用这个特殊变量,就和使用普通变量类似的。我们可以在 if-then 语句中使用 -ne 测试命令行参数数量。
存在一个问题:
既然$#
变量可以获取参数的总数,那么很自然会想到变量${$#}
就代表了最后一个命令行参数变量。但这在 shell 中十错误的写法,因为不能再花括号中使用$
符号,必须将美元符换成感叹号${!#}
。
2.2. 获取所有的数据
$*
和$@
变量可以用来轻松访问所有的 shell 参数。这两个变量都能够在单个变量中存储所有的命令行参数。这两个变量的区别是:$*
变量会将命令行上提供的所有参数当作一个单词保存($*
变量会将所有参数当成单个参数),$@
变量会将命令行上提供的所有参数当作同一字符串中的多个独立的单词保存($@
变量会单独处理每个参数)。
3. 移动数变量
bash shell 工具箱中另一件工具是
shift
命令。bash shell 的shift
命令能够用来操作命令行参数。跟字面意思一样, shift 命令会根据它们的相对位置来移动命令行参数。在每执行一次shift
命令时,默认情况下它会将每个参数变量向左移动一个位置。所以,变量$3
的值会移到$2
中,变量$2
的值会移到$1
中,而变量$1
的值则会被删除。但是注意,变量$0
的值,也就是程序名,则不会改变。
**那么移动参数的作用是什么呢?**这是遍历命令行参数的另一个好方法,尤其是在你不知道到底有多少参数时。可以只操作第一个参数,通过移动参数,然后继续操作第一个参数,来达到访问所有参数的目的。
使用方法:
echo
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
count=$[ $count + 1 ]
shift
done
4. 处理选项
选项是什么:我们在使用 linux 系统的过程中总是习惯使用命令行来操作各种各样的文件,比如列出所有的文件
ls -l
其中ls
是命令,-l
是命令的选项,所以选项就是跟在单破折线后面的单个字母,它能改变命令的行为。
4.1. 使用 getopt 命令
getopt
命令是一个在处理命令行选项和参数时非常方便的工具。它能够识别命令行参数,从而在脚本中解析它们时更方便。
getopt 命令格式:
Usage:
getopt <optstring> <parameters>
getopt [options] [--] <optstring> <parameters>
getopt [options] -o|--options <optstring> [options] [--] <parameters>
<optstring>
是这个过程的关键所在。它定义了命令行有效的选项字母,还定义了哪些选项字母需要跟随参数值。
getopt 命令的标准 字符串:
选项:
-a, --alternative 允许以单开头的长选项 -
-l, --longoptions <longopts> 要识别的长选项
-n, --name <progname> 报告错误的名称
-o, --options <optstring> 要识别的短选项
-q, --quiet 通过 getopt(3) 禁用错误报告
-Q, --quiet-output 无正常输出
-s, --shell <shell> 将引用约定设置为 <shell> 的引用约定
-T, --test 测试 getopt(1) 版本
-u, --unquoted 不引用输出
-h, --help 显示此帮助
-V, --version 显示版本
getopt 命令的定义:
选项字符都可以随意的组合,下面字符是自定义的格式,字符的选择以及字符间组合并不需要按照下面这样,可以随机选择,随机组合
getopt a
getopt ab
getopt abcd
如果选项需要跟随参数值,那么在定义所选择的选项字符的后面需要跟随冒号:
getopt a:
getopt a:b:
getopt ab:
实际使用:
getopt ab:cd
-a -b 10 -c -d 20 30 黑色的为我们在实际使用时,根据我们定义的<optstring>
字符串规则输入的参数
getopt ab:cd
-a -b 10 -cd 20 30 还可以这样,getopt
命令会自动将-cd
分成两个单独的选项变成-c -d
如果指定了一个不在
<optstring>
中的选项,默认情况下,getopt
命令会产生一条错误消息。
$ sh getopt.sh -abc
getopt: unknown option -- c
-a -b --
4.2. 使用 getopts 命令
5. 选项标准化
在创建 shell 脚本时,显然可以控制具体怎么做。你完全可以任意决定用哪些字母选项以及它们的用法。但有些字母选项在Linux世界里已经拥有了某种程度的标准含义。如果能在自己编写的 shell 脚本中支持这些选项,脚本看起来能更易用些,也会显得更加的专业。
----------------------------------
选项 | 描 述
----------------------------------
-a | 显示所有对象
-c | 生成一个计数
-d | 指定一个目录
-e | 扩展一个对象
-f | 指定读入数据的文件
-h | 显示命令的帮助信息
-i | 忽略文本大小写
-l | 产生输出的长格式版本
-n | 使用非交互模式(批处理)
-o | 将所有输出重定向到的指定的输出文件
-q | 以安静模式运行
-r | 递归地处理目录和文件
-s | 以安静模式运行
-v | 生成详细输出
-x | 排除某个对象
-y | 对所有问题回答yes
-------------------------------
6. 获取用户输入
命令行选项和参数是从脚本用户处获得输入的一种重要方式,但是有时脚本的交互性还需要更强一些。比如你想要在脚本运行时问个问题,并等待运行脚本的人来回答。bash shell 为此提供了
read
命令。这类似 C 语言的scanf()
函数,可以用来读取用户的终端输入。
6.1. 基本的读取
read
命令从标准输入(键盘输入)或另一个文件描述符中接受输入。在收到输入后,read
命令会将数据放进一个变量。比如下方的使用方式:
echo -n "Enter your name: "
read name
echo "Hello $name, welcome!"
echo
命令使用了-n
选项。该选项不会在字符串末尾输出换行符,允许脚本用户紧跟其后输入数据,而不是下一行。
read
命令包含了-p
选项,允许你直接在read
命令行指定提示符或其他的提示内容。而不需要使用echo
来输出提示内容。
read -p "Enter your name:" name
echo "Hello $name, welcome!"
6.2. 读取超时
脚本很可能会一直等待用户的输入。如果不管是否有数据输入,脚本都必须继续执行,可以用
-t
选项来指定一个计时器。-t
选项指定了read
命令等待输入的秒数。当计时器过期后,read
命令会返回一个非零退出状态码,表示超时。
if read -t 5 -p "Enter your name: " name
then
echo "Hello $name, welcome!"
else
echo
echo "Sorry, time out! "
fi
6.3. 隐藏方式读取
有时你需要从脚本用户处得到输入,但又不在屏幕上显示输入信息。其中典型的例子就是 linux 系统输入密码,除此之外还有很多其他需要隐藏的数据类型。
read
命令-s
选项可以避免在read
命令中输入的数据出现在显示器上(实际上,数据会被显示,只是read
命令会将文本颜色设成跟背景色一样)。
6.4. 从文件中读取
可以用
read
命令来读取 linux 系统上文件里保存的数据。每次调用read
命令,它都会从文件中读取一行文本。当文件中再没有内容时,read
命令会退出并返回非零退出状态码。最难的部分是将文件中的数据传给read
命令。最常见的方法是对文件使用cat
命令,将结果通过管道直接传给含有read
命令的while
命令。
count=1
cat filename | while read line
do
echo "Line $count: $line"
count=$[ $count + 1]
done
echo "Finished processing the file"