向addem传递两个参数10 30
./addem 10 30
读取位置参数:$0
是程序名,$1
到$9
是第一个到第九个参数,之后的参数需要${10}
这种才可以。参数与参数之间按照空格分开。
#!/bin/bash
#实现参数读取并做乘法
total=$[ $1 * $2 ]
echo "The first param is $1"
echo "The second param is $2"
echo "The total value is $total"
echo "The second param is ${10}"
读取脚本名:$0
传递的是完整的脚本路径,使用basename得到不包含路径的脚本名,从而根据不同的脚本名实现不同的功能。
#!/bin/bash
#得到脚本的路径名和脚本名
path_name=$0
script_name=$(basename $0)
echo "The path of script is $path_name"
echo "The script name is $script_name"
测试参数: 脚本不加参数运行,会产生错误信息,因此最好添加相关参数测试
使用-n
测试参数中是否有数据
#!/bin/bash
#检测参数1是否正常输入参数
if [ -n "$1" ]
then
echo "你输入的第一个参数为 $1 "
else
echo "你没有输入任何的参数"
fi
参数统计
有些记录命令行的参数相关变量,如$#
是记录命令行参数的总的个数
#!/bin/bash
#测试参数总的个数,有两个就做加法,否则就报错
if [ $# -ne 2 ]
then
echo "Usage: $(basename $0) a b"
echo
else
total=$[ $1 + $2 ]
echo
echo "The total is $total"
echo
fi
既然$#
是记录了总的个数,那么${$#}
应该代表最后一个命令行参数,但是不是这样的,${!#}
才是正确的得到最后一个参数变量。
#!/bin/bash
#测试得到最后一个参数
echo "The last param is ${$#}"
echo "The last param is ${!#}"
抓取所有数据
$*
:所有参数合并为一个整体的字符串
$@
:提供所有参数的独立字符串
#!/bin/bash
#测试$*和$@
count=1
for param in $*
echo "\$* parameter #$count = $param"
count=$[ $count + 1 ]
done
count=1
for param in $@
do
echo "\$@ parameter #$count = $param"
count=$[ $count + 1 ]
done
运行结果:
貌似和我们介绍的有所不同,好吧,注意我们在遍历的时候写明:
for param in $@
而$*
和$@
两个的区别只能从"$*"
和"$@"
看出来,即写做
for param in "$*"
for param in "$@"
在你不知道到底有多少个参数的时候,你可以使用shift将之后变量的值转移到之前,如$2
转移到$1
,同时$1
就被销毁了。
#!/bin/bash
#简单测试shift
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
count=$[ $count + 1 ]
shift
done
注意shift n
表示具体移动多少个参数
处理简单的选项
使用case提取参数并判定是否为某个选项
#!/bin/bash
#使用shift依次判断每个参数是否为选项
count=1
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" ;;
*) echo "$1 is not the option" ;;
esac
shift
done
运行结果:
分离参数和选项
如果一个脚本既要使用参数又要使用选项,这个时候需要一个特殊的参数帮助辨识哪些是参数哪些是选项,这里使用"–"来分离。
#!/bin/bash
#处理选项
count=1
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 the option" ;;
esac
shift
done
#处理参数
count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
执行结果:
处理带值的选项
例如下面这个例子,test1
应该是为-a
这个选项服务的
./testing.sh -a test1 -b -c -d test2
只需要在对应的选项插入读取参数的相关语句
#!/bin/bash
#处理选项
count=1
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2" #读取-b之后的参数
echo "Found the -b option with the param $param"
shift;; #跳过-b之后的这个参数
-c) echo "Found the -c option" ;;
--) shift #只是为了跳过--这个参数
break;;
*) echo "$1 is not the option" ;;
esac
shift
done
#处理参数
count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
运行结果
上述的命令只能处理单个选项,对于复合选项毫无能力,因此介绍下面的getopt命令
getopt命令
getopt命令格式如下
getopt optstring parameters
optstring中列出你要在脚本中用到的每个命令行选项字母。然后,在每个需要参数值的选项字母后加一个冒号。getopt命令会基于你定义的optstring解析提供的参数。
例如:
#ab:cd说明有4个选项,其中b需要有参数
$getopt ab:cd -a -b test1 -cd test2 test3
-a -b test1 -c -d -- test2 test3
如果使用了没有声明的参数
$getopt ab:cd -a -b test1 -cde test2 test3
getopt: invalid option -- e
-a -b test1 -c -d -- test2 test3
可以使用-q
忽略这个参数
$getopt -q ab:cd -a -b test1 -cde test2 test3
-a -b 'test1' -c -d -- 'test2' 'test3'
脚本中使用getopt
仔细思考一下,使用getopt可以得到格式化的输入。但是在脚本中执行时,无法将格式化的输入作为输入执行脚本。因此我们使用set --
,它会将格式化后的命令替换掉原始的命令。
#!/bin/bash
#处理输入命令,相比上一个实例代码,只多了下面这行
set -- $(getopt -q ab:cd "$@")
#处理选项
count=1
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2" #读取-b之后的参数
echo "Found the -b option with the param $param"
shift;; #跳过-b之后的这个参数
-c) echo "Found the -c option" ;;
--) shift #只是为了跳过--这个参数
break;;
*) echo "$1 is not the option" ;;
esac
shift
done
#处理参数
count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
运行结果
但是这个代码仍然存在问题,无法合理的处理带空格和引号的参数值
使用更高级的optgets
getopts命令格式:
getopts optstring variable
optstring值:
有效的选项字母都会列在optstring中,如果选项字母要求有个参数值,就加一个冒号。要去掉错误消息的话,可以在optstring之前加一个冒号。
getopts命令:
将当前参数保存在命令行中定义的variable中。
两个重要的环境变量
OPTARG环境变量就会保存选项后的参数值。
OPTIND环境变量保存了参数列表中getopts正在处理的参数位置。这样你就能在处理完选项之后继续处理其他命令行参数了。
示例代码:
#!/bin/bash
#使用getopts得到选项参数分割,注意case下面的选项不是-a),并且是遍历完所有参数之后才实现位置转移的
while getopts :ab:cd opt
do
case "$opt" in
a) echo "This is -a option";;
b) echo "This is -b option with value $OPTARG";;
c) echo "This is -c option";;
d) echo "This is -d option";;
*) echo "Unknown option:$opt" ;;
esac
done
#跳过当前已经处理完毕的参数
shift $[ $OPTIND - 1 ]
#遍历参数
count=1
for param in "$@"
do
echo "Parameter $count: $param"
count=$[ $count + 1 ]
done
选项标准化:
Linux命令对于关键的参数已经有具体的意义了,参照
基本读取
使用read从标准输入得到变量值
#!/bin/bash
#-n表示不换行得到输入
echo -n "Enter your name:"
read name
echo "Hello $name, welcome to my program."
#read -p可以输出一些提示信息得到单个输入
read -p "Please enter your age: " age
days=$[ $age * 365 ]
echo "That makes you over $days days old;"
#read 得到多个输入
read -p "Please enter your first and last: " first last
echo "Checking data for $first, $last..."
#如果不指定变量,所有输入会保存在REPLY中
read -p "Enter the name which will save in:"
echo "hello, welcome to $REPLY"
超时判断
为了防止一直等待,使用-t
设置等待的秒数,超时之后返回非0退出码。
也可以设置-n num
读取指定数量的输入退出。
#!/bin/bash
#设置超时时间的输入
if read -t 5 -p "Please enter your name:" name
then
echo "Hello $name, welcome to my script"
else
echo "Sorry, too slow!"
fi
#设置指定数量的输入
read -n1 -p "DO you want to continue [Y/N]?" answer
case $answer in
Y | y) echo "fine, continue on...";;
N | n) echo "OK, goodbye"
exit;;
esac
echo "This is the end of the scipt"
隐藏方式读取
-s
选项可以避免在read输入的数据出现在显示器上
#!/bin/bash
read -s -p "Enter your password: " pass
echo
echo "Is your password really $pass? "
从文件读取
#!/bin/bash
# reading data from a file
#
count=1
cat test | while read line
do
echo "Line $count: $line"
count=$[ $count + 1]
done
echo "Finished processing the file"