特殊环境变量 | 含义 |
$1 $2..$9,${10}... | 表示脚本的第n个参数 |
$0 basename $0 |
脚本名(含路径) 脚本名(不含路径) |
$# ${!#} |
参数总数 最后一个参数值 |
$* |
将所有参数作为一个字符串保存 |
$@ | 将n个参数作为n个字符串保存 |
向shell脚本传递数据最基本的方法是使用命令行参数,在脚本运行时指定参数,例如:
./add.sh 10 30
./output.sh 'Hello World' #带空格的参数需加引号,单双引号均可
shell提供位置参数(一组特殊环境变量集合),分别用$1 $2..$9表示第一至第九个参数,10之后写法为${10}。
有两个比较特殊的参数$0和$#,$0表示执行的脚本名(含路径),$#表示参数的个数
如果只想获取脚本名不需要路径,可以使用basename命令
当脚本需要输入参数才能正常工作时,应该使用 if [ -n $1] 或者 if [ $# = 2] 判断参数数量是否正确。
你可能会想,既然$#表示参数的个数,${$#}是不是就代表最后一个参数的值?实际上不是,shell不允许在{}中使用$符。正确的写法应该是${!#}。
想要获取所有命令行参数,可以使用$*或$@,$*将所有参数视为一个字符串,$@则将每个参数视为一个字符串。
#!/bin/bash
echo "print each param from \"\$*\""
for var in "$*"
do
echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do
echo "$var"
done
运行脚本
./test.sh a b c d
print each param from "$*"
a b c d
print each param from "$@"
a
b
c
d
shift命令默认会将每个变量向左移一位(相当于shift 1),$3->$2,$2->$1,并删除原$1的值。当你不确定到底会有几个参数时,这是个好办法,你可以只操作第一个变量,移动参数,然后继续操作新的第一个变量。
#!/bin/bash
# 找出文件(可指定多个文件名)中长度最长的单词,$1为文件名
while [[ -n $1 ]] # 参数不为空,即还有待查找文件
do
if [[ -r $1 ]];then # 文件存在且有读权限
max_word=
max_len=0
for i in $(strings $1) # strings程序(包含在binutils包中)为每一个文件产生一个可读的文本格式的words列表
do
len=$(echo $i | wc -c) # wc -c统计字符数,即计算每个单词长度
if ((len > max_len));then
max_len=$len
max_word=$i
fi
done
echo "$1:'$max_word' ($max_len characters)"
fi
shift # 参数向左偏移,即开始查找下一个文件
done
也可以利用 shift n 指定每个变量向左移几位
#! /bin/bash
while [ -n "$1" ] # 加双引号表示强制变量为字符串格式,对于字符串的比较,变量取值一定要加双引号
do
echo $1
shift 2
done
有时脚本后不仅有参数,还有选项,例如
./mypara.sh -a -b param1 -d
最简单的可以使用case处理选项,确定哪些选项后可能有参数,会有几个参数,在对应case的中处理参数。
#! /bin/bash
# 假设选项有-a -b -c,仅-b后会有1个参数
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option";;
-b) param="$2"
echo "Found the -b option,with parameter $param"
shift ;; #参数多占一位,需要挪走
-c) echo "Found the -c option";;
--) shift
break ;;
*) echo "$1 is not the an option";;
esac
shift
done
合并选项例如 ll -rth,这时前面的方法就没法解决问题,需要使用到 getopt 命令。
getopt 能够识别一系列任意形式的选项和参数,并自动将它们转为适当格式。
getopt optstring parameters
optstring 是其中的关键,它定义了命令行有效的选项字母,以及哪些选项需要参数(在字母后加:),例如:
getopt ab:cd -a -b test1 -cd test2 test3
#选项有-a -b -c -d,-b后有:说明-b后面会有参数
输出会是转换后的格式,其中test2 test3被识别为额外参数,用--分隔开
如何在脚本中使用getopt 命令?可以将getops命令输出(格式化后的参数)传给set,set -- 命令会将命令行参数替换成set命令的命令行值。
#/bin/bash
###################################
# Extract command line options & values with getopt
set -- $(getopt -q ab:cd "$@")
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not option";;
esac
shift
done
#输出额外参数
count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
你会发现这个脚本跟前面整体差别不大,但它提供了合并选项的处理。
但是,getopt 命令并不擅长处理带空格和引号的参数值,例如
./mypara.sh -a -b param1 -c "test1 test2" test3
可以看到它并没有将"test1 test2"当作整体处理,只是用空格作分隔符。
getopts基本上是一个增强版:
# 用法与getopt基本相同
getopts optstring variables
# 要忽略错误消息,需在optstring前加冒号:,即
getopts :optstring variables
# variables中会保存当前参数
注意getopts解析后的命令行选项不带-,使用case匹配时也不需加,$OPTARG中存储选项后参数
#!/bin/bash
###################################
# simple demonstration of the getopts command
#
echo
while getopts :ab:c opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with parameter value $OPTARG" ;; # $OPTARG中存储选项后参数
c) echo "Found the -c option" ;;
*) echo "Unknown option: $opt" ;;
esac
done
可以将选项和参数合在一起,中间不加空格;还可以将所有未定义参数统一输出成问号?
read命令可从标准输入(键盘)或另一个文件中接收输入,并保存到一个变量,下面来看其常用用法。
最简单的用法,-p会显示指定的输入提示符
#! /bin/bash
read -p "Input your name: " name
echo "Hello $name"
可以输入多个参数
#! /bin/bash
read -p "Input your name and age: " name age
echo "Hello $name,age $age"
如果变量数>输入参数,会从前往后分配,后面的变量为空;如果变量数<输入参数,多余的参数会全存在最后一个变量
若不指定参数,read会将接收到的数据存入特殊变量REPLY中
#! /bin/bash
read -p "Input your name: "
echo "Hello $REPLY"
如果用户一直不输入,read默认会一直等,-t选项可以设置定时器指定等待秒数,超时后read命令会返回非0退出状态码。
#! /bin/bash
if read -t 5 -p "Input your name: "
then
echo "Hello $REPLY"
else
echo #避免Timeout直接输出在提示语句后面
echo "Timeout"
fi
read命令的 “-n数字” 选项可指定在用户输入指定字符数后自动退出,无需按回车。
#! /bin/bash
read -n1 -p "Please input a character: "
echo
echo "Your input is $REPLY"
有时用户希望将输入传入脚本但又不在屏幕上显示,典型情况就是输密码。read命令的-s选项就可以做到(实际也会显示,只是read命令将其改为了与屏幕底色相同)。
#! /bin/bash
read -s -p "Please input your password: "
echo
echo "Is your password really $REPLY"
每次调用read命令会从文件中读取一行文本,当文件中再没有内容时,read会以非0状态码退出。最常见的方法是cat文件,将结果通过管道传给通过while命令的read命令。
#! /bin/bash
# reading data from a file
count=1
cat breaktest.sh | while read line
do
echo "Line $count: $line"
count=$[ $count + 1 ]
done
echo "--- end of file ---"