1 处理脚本参数
一个正常的脚本在处理参数时,应该可以做到:
-
脚本参数无序也能执行
-
短选项要支持连写
其实要真的自己写代码去处理这些参数,我估计这工作量比一些普通的脚本都要大得多。。。好在Linux中内置了一个命令getopt
,这个命令可以帮我处理这两个问题
[root@localhost ~]# getopt -q adp:s:h -ha -s /bin/nologin -p 123 userlist
-h -a -s '/bin/nologin' -p '123' -- 'userlist'
在这里,我们将adp:s:h
和-ha -s /bin/nologin -p 123 userlist
作为 getopt
的两个参数
adp:s:h
:当下一个参数出现-a
、-d
、-p 参数
、-s 参数
、-h
时,将会把它们解析成正常的选项+参数
的形式,并且带参数的选项放在最后面,短选项支持连写,各个选项可以乱序- 选项后面的冒号表示该选项需要参数
- 如果该选项可以的参数不是必要的话,可以在选项后面加两个冒号
再看输出的结果:getopt
这个命令将我们“复杂乱序”的参数变成了一条格式整齐的参数,其中不带参数的短选项被放在了最前面,其次是带参数的选项,最后由 -- ‘userlist’
结尾,这表示不带选项的参数将会被放在最后面。值得注意的是,不带选项的参数有且仅有一个且在输入前也需要放在最后面
解决了参数格式的问题,还需要解决的问题是,在传入参数后,脚本怎么知道这些参数第几个是什么选项,有几个选项呢。这就需要用到shell中自带的两个函数set
和shift
set
:这个函数用于将指定的字符串替换当前的参数列表
# 用法
set -- $STR
shift [N]
:这个函数用于弹出指定个数的参数
# 用法
shift # 表示将第一个参数弹出
shift 2 # 表示将前两个参数弹出
看到这里可能你还是一头雾水,知道这两个函数又有什么用呢?我们再来看一般在脚本中会如何使用这两个函数
#!/bin/bash
# $@表示将脚本的全部参数
# 因getopt这个命令会将各个选项的参数转换成'参数'的形式,并不利于我们直接使用它,所以在解析后先将其用sed命令删去
opt=`getopt -q adp:s:h $@ | sed "s/'//g"`
# 将脚本参数改成格式化后的参数
set -- $opt
# 这里使用了一个死循环,每次都判断第一个参数是什么选项,然后做出对应处理后将其弹出,这样就可以逐个处理选项了
while :; do
case $1 in
-a)
...
shift
;;
-d)
...
shift
;;
-p)
# -p是带选项的参数,所以一次要弹出两个参数
...
shift 2
;;
-s)
...
shift 2
;;
--)
# 在遇到--后,表示所有选项都已经处理完了,只剩下最后一个不带选项的参数,这时弹出选项后退出循环,脚本中的$1就变成了这个不带选项的参数
shift
break
;;
*)
# 当遇到其他无法解析的选项时,输出错误提示并退出脚本的运行
echo "Error"
exit 1
esac
done
至此,一个脚本的参数就基本能很好的处理完成了
2 脚本实战
写一个用户脚本:这个脚本用于批量创建用户,并且可以指定密码和使用的shell
- 脚本格式:./script_file [ -h | -a | -d | -p PASSWORD | -m | -s SHELL ] USER_LIST_FILE
- -a :创建用户列表文件中的用户
- -d:删除用户列表文件中的用户
- -p PASSWORD:设置用户统一密码
- -m:使用默认密码redhat
- -s SHELL:指定用户的默认shell,如不指定默认/bin/bash
- -h:显示帮助信息
- USER_LIST_FILE文件内容:每行一个用户名
- 注意事项:
- 脚本参数无序也能执行
- 脚本根据不同情况返回不同的状态码
- 参数错误能报错
- 短选项要支持连写
- 不显示多余的输出信息
- 用户已存在提示
#!/bin/bash
#./script_file [ -h | -a | -d | -p PASSWORD | -m | -s SHELL ] USER_LIST_FILE
opt=`getopt -q adp:s:h $@ | sed "s/'//g"`
set -- $opt
#默认密码
def_passwd=redhat
#默认shell
def_shell=/bin/bash
#一个参数都没有加:提示用法
if [ $# -eq 1 ]; then
echo "Usage: ./script_file [-h|-a|-d|-p PASSWORD|-s SHELL] USER_LIST_FILE"
echo "Try use '-h' to get more information."
exit 2
fi
#只有一个参数:判断是否为-h,不是则报错
#if [ $# -eq 2 ]; then
# if [[ $1 = -h ]]; then
# #调用外部获取帮助脚本
# /root/get_help.sh
# exit 2
# else
# echo "Error, need at least 1 arg!!!"
# exit 1
# fi
#fi
#使用无限循环获取所有参数
while :; do
case $1 in
-h)
#调用外部脚本
/root/get_help.sh
shift
;;
-a)
#添加和删除不能同时使用
if [[ $flag != del ]]; then
flag=add
shift
else
#报错退出
echo "Error, '-a' and '-d' can not be used together!!!"
exit 1
fi
;;
-d)
#添加和删除不能同时使用
if [[ $flag != add ]]; then
flag=del
shift
else
#报错退出
echo "Error, '-a' and '-d' can not be used together!!!"
exit 1
fi
;;
-p)
def_passwd=$2
shift 2
;;
-s)
def_shell=$2
shift 2
;;
--)
shift
break
;;
*)
#提示选项不支持
echo "Error, unsupported option '$1' !!!"
exit 1
esac
done
#判断参数是否为空
if [ -z $1 ]; then
echo "Error, need userlist file"
exit 1
fi
#查询文件是否存在
find $1 > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "$1 does not exist!!!"
exit 1
fi
case $flag in
add)
while read user; do
id $user &> /dev/null
if [ $? -eq 0 ]; then
echo "$user already exist."
else
useradd -s $def_shell $user
#当添加失败时输出错误信息,shell的类型没加判断可能会出错
if [ $? -eq 0 ]; then
echo "user $user added."
echo $def_passwd | passwd --stdin $user > /dev/null 2>&1
else
echo "user $user add failed, please check."
fi
fi
done < $1
;;
del)
while read user; do
id $user &> /dev/null
if [ $? -eq 1 ]; then
echo "user $user do not exist."
else
userdel -r $user
echo "user $user deleted."
fi
done < $1
;;
*)
echo "Error, need '-a' or '-d' option to execute this script"
exit 1
esac
#!/bin/bash
get_help(){
echo "Descreption: this script is use to manage user"
echo -e "\t-a\t\tcreate the user"
echo -e "\t-d\t\tdelete the user"
echo -e "\t-p PASSWORD\tset the password of user in stand of defualt [redhat]"
echo -e "\t-s SHELL_TYPE \tset the shell of user in stand of defualt [/bin/bash]"
echo -e "\t-h\t\tget the help of this script"
}
get_help
忘记写-m,-m与-p不能同时用的判断和-a与-d的判断类似,所以偷个懒就不补了
想试一下脚本调用脚本还有练一下函数的使用,查看帮助的代码写到了另外一个脚本get_help.sh里
测试用例:
- 不写参数
[root@localhost ~]# ./script_file.sh
Usage: ./script_file [-h|-a|-d|-p PASSWORD|-s SHELL] USER_LIST_FILE
Try use '-h' to get more information.
- 只写一个参数-h
[root@localhost ~]# ./script_file.sh -h
Descreption: this script is use to manage user
-a create the user
-d delete the user
-p PASSWORD set the password of user in stand of defualt [redhat]
-s SHELL_TYPE set the shell of user in stand of defualt [/bin/bash]
-h get the help of this script
- 只写一个不为-h的参数
[root@localhost ~]# ./script_file.sh -a
Error, need userlist file
[root@localhost ~]# ./script_file.sh userlist
Error, need '-a' or '-d' option to execute this script
- 默认添加测试
[root@localhost ~]# ./script_file.sh -a userlist
user k1 added.
user k2 added.
user k3 added.
[root@localhost ~]# ./script_file.sh -a userlist
k1 already exist.
k2 already exist.
k3 already exist.
[root@localhost ~]# cat /etc/passwd | grep '^k[1-3]'
k1:x:1011:1012::/home/k1:/bin/bash
k2:x:1012:1013::/home/k2:/bin/bash
k3:x:1013:1014::/home/k3:/bin/bash
- 指定密码、shell、选项无序、连写测试
[root@localhost ~]# ./script_file.sh -ah -s /bin/nologin -p 123 userlist
Descreption: this script is use to manage user
-a create the user
-d delete the user
-p PASSWORD set the password of user in stand of defualt [redhat]
-s SHELL_TYPE set the shell of user in stand of defualt [/bin/bash]
-h get the help of this script
user k1 added.
user k2 added.
user k3 added.
[root@localhost ~]# cat /etc/passwd | grep '^k[1-3]'
k1:x:1011:1012::/home/k1:/bin/nologin
k2:x:1012:1013::/home/k2:/bin/nologin
k3:x:1013:1014::/home/k3:/bin/nologin
- 删除测试
[root@localhost ~]# ./script_file.sh -d userlist
user k1 deleted.
user k2 deleted.
user k3 deleted.
[root@localhost ~]# ./script_file.sh -d userlist
user k1 do not exist.
user k2 do not exist.
user k3 do not exist.
[root@localhost ~]# ./script_file.sh -ad userlist
Error, '-a' and '-d' can not be used together!!!
- 文件错误提示
[root@localhost ~]# ./script_file.sh -a userlist1
userlist1 does not exist!!!