shell脚本读取命令行的参数
转至:https://www.cnblogs.com/eternityz/p/13879836.html
前提
在编写shell程序时经常需要处理命令行参数
选项与参数:
如下命令行:
./test.sh -f config.conf -v --prefix=/home
-f为选项,它需要一个参数,即config.conf,
-v 也是一个选项,但它不需要参数。
--prefix我们称之为一个长选项,即选项本身多于一个字符,它也需要一个参数,用等号连接,当然等号不是必须的,
/home可以直接写在--prefix后面,即--prefix/home,
更多的限制后面具体会讲到。
一.手工处理方式(已验证)
在手工处理方式中,首先要知道几个变量,还是以上面的命令行为例:
$0:./test.sh,即命令本身,相当于c/c++中的argv[0]
$1:-f,第一个参数.
$2:config.conf
$3, $4 ... :类推。
$#: 参数的个数,不包括命令本身,上例中$#为4.
$@:参数本身的列表,也不包括命令本身,如上例为 -f config.conf -v --prefix=/home
$*:和$@相同,但"$*" 和 "$@"(加引号)并不同,"$*"将所有的参数解释成一个字符串,而"$@"是一个参数数组。
例子
#!/bin/bash
for arg in "$*"
do
echo $arg
done
for arg in "$@"
do
echo $arg
done
执行./test.sh -f config.conf -n 10 会打印:
#./test.sh -f config.conf -n 10 # 这是"$*"的输出
-f config.conf -n 10 #以下为$@的输出
-f
config.conf
-n
10
所以,手工处理的方式即对这些变量的处理。因为手工处理高度依赖于你在命令行上所传参数的位置,所以一般都只用来处理较简单的参数。
例如:
./test.sh 10
而很少使用./test -n 10这种带选项的方式。
典型用法为:
#!/bin/bash
if [ x$1 != x ]
then
#...有参数逻辑
else
then
#...没有参数逻辑
fi
为什么要使用 x$1 != x 这种方式来比较呢?(x就是任意的一个字符,也可以是别的)
想像一下这种方式比较:
if [ -n $1 ] #$1不为空
但如果用户不传参数的时候,$1为空,这时就会变成 [ -n ] ,所以需要加一个辅助字符串来进行比较。
手工处理方式能满足大多数的简单需求,配合shift使用也能构造出强大的功能,但在要处理复杂选项的时候建议用下面的两种方法。
二.getopts/getopt
处理命令行参数是一个相似而又复杂的事情,为此,c提供了getopt/getopt_long等函数,
c++的boost提供了options库,在shell中,处理此事的是getopts和getopt.
getopts和getopt功能相似但又不完全相同,其中getopt是独立的可执行文件,而getopts是由bash内置的。
./test.sh -a -b -c : 短选项,各选项不需参数
./test.sh -abc : 短选项,和上一种方法的效果一样,只是将所有的选项写在一起。
./test.sh -a args -b -c :短选项,其中-a需要参数,而-b -c不需参数。
./test.sh --a-long=args --b-long :长选项
先来看getopts,它不支持长选项。
使用getopts非常简单:
#test.sh
#!/bin/bash
while getopts "a:bc" arg #选项后面的冒号表示该选项需要参数
do
case $arg in
a)
echo "a's arg:$optarg" #参数存在$optarg中 b)
echo "b" c)
echo "c" ?) #当有不认识的选项的时候arg为?
echo "unkonw argument"
exit 1 esac
done
现在就可以使用:
./test.sh -a arg -b -c
或
./test.sh -a arg -bc
来加载了。
应该说绝大多数脚本使用该函数就可以了,如果需要支持长选项以及可选参数,那么就需要使用getopt.
getopt自带的一个例子:
#!/bin/bash
# a small example program for using the new getopt(1) program.
# this program will only work with bash(1)
# an similar program using the tcsh(1) script language can be found
# as parse.tcsh
# example input and output (from the bash prompt):
# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "
# option a
# option c, no argument
# option c, argument `more'
# option b, argument ` very long '
# remaining arguments:
# --> `par1'
# --> `another arg'
# --> `wow!*\?'
# note that we use `"$@"' to let each command-line parameter expand to a
# separate word. the quotes around `$@' are essential!
# we need temp as the `eval set --' would nuke the return value of getopt.
#-o表示短选项,两个冒号表示该选项有一个可选参数,可选参数必须紧贴选项
#如-carg 而不能是-c arg
#--long表示长选项
#"$@"在上面解释过
# -n:出错时的信息
# -- :举一个例子比较好理解:
#我们要创建一个名字为 "-f"的目录你会怎么办?
# mkdir -f #不成功,因为-f会被mkdir当作选项来解析,这时就可以使用
# mkdir -- -f 这样-f就不会被作为选项。
temp=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
-n 'example.bash' -- "$@"`
if [ $? != 0 ] ; then echo "terminating..." >&2 ; exit 1 ; fi
# note the quotes around `$temp': they are essential!
#set 会重新排列参数的顺序,也就是改变$1,$2...$n的值,这些值在getopt中重新排列过了
eval set -- "$temp"
#经过getopt的处理,下面处理具体选项。
while true ; do
case "$1" in
-a|--a-long) echo "option a" ; shift ;;
-b|--b-long) echo "option b, argument \`$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. as we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" in
"") echo "option c, no argument"; shift 2 ;;
*) echo "option c, argument \`$2'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "internal error!" ; exit 1 ;;
esac
done
echo "remaining arguments:"
for arg do
echo '--> '"\`$arg'" ;
done
比如使用
./test -a -b arg arg1 -c
你可以看到,命令行中多了个arg1参数,在经过getopt和set之后,命令行会变为:
-a -b arg -c -- arg1
1指向−a, 1指向−a, 2指向-b,3指向arg, 3指向arg, 4指向-c,$5指向--,而多出的arg1则被放到了最后。
三.总结
一般小脚本手工处理也就够了,getopts能处理绝大多数的情况,getopt较复杂,功能也更强大。
站在巨人肩膀上摘苹果
shell脚本读取命令行的参数的更多相关文章
- Shell脚本中判断输入参数个数的方法投稿:junjie 字体:[增加 减小] 类型:转载
Shell脚本中判断输入参数个数的方法 投稿:junjie 字体:[增加 减小] 类型:转载 这篇文章主要介绍了Shell脚本中判断输入参数个数的方法,使用内置变量$#即可实现判断输入了多少个参数 ...
- Shell脚本编写3---Shell 传递参数
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推…… 执行脚本,查看输出结果: 另外 ...
- awk如何区分shell脚本传进来的参数和自身的参数?awk如何获取shell脚本传进来的参数;awk中如何执行shell命令
问题:对于shell脚本,$0表示脚本本身,$1表示脚本的第一个参数,$2……依次类推:对于awk,$1表示分割后的第一个字段,$2……依次类推.那么对于shell脚本中的awk如何区分两者呢? 答案 ...
- 【转】shell脚本中如何传入参数
(1)直接用$1,$2取传入的参数vim /root/test.sh#!/bin/bashif [ $1 == "start" ] then echo "do ...
- 【shell脚本】优化内核参数===
一.Linux内核参数优化 Sysctl命令用来配置与显示在/proc/sys目录中的内核参数.如果想使参数长期保存,可以通过编辑/etc/sysctl.conf文件来实现. 命令格式: sysct ...
- shell脚本获取传递的参数
1 脚本编写 #!/bin/bash 2 解释 $n 表示是第几个参数 $0 表示脚本命令本身 3 执行效果
- 编写SHELL脚本--判断用户的参数
测试语句格式: [ 条件表达式 ] 常见的几种形式: [ -d /etc ] 判断/etc是不是一个目录类型, [ -e /etc/php.ini ] 判断/etc/php.ini 文件是否存在 [ ...
- [shell]shell脚本传入不固定参数的写法,如--help等
最近在调试一个wifi模块,需要传一些不固定的参数,一下一个参数解析的函数可以搞定这个事情,里面内容好多部分是从一个example中剽窃而来(窃喜) #!/bin/bash # writen by a ...
- Linux程序设计 读笔2 Shell脚本
第二章 Shell程序设计 四.管道和重定向 1 重定向输出 ls -l > lsoutput.txt ps >> lsoutput.txt >>表示附加到一个文件中 文 ...
随机推荐
- MySQL数据库本地事务原理
在经典的数据库理论里,本地事务具备四大特征: 原子性 事务中的所有操作都是以原子的方式执行的,要么全部成功,要么全部失败: 一致性 事务执行前后,所有的数据都应该处于一致性状态---即要满足数据库表的 ...
- 报错org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.mybatis.spring.SqlSessionFactoryBean]
超级大坑 org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.mybati ...
- Kubernetes的Resource和Dashboard(十三)
一.Resource和Dashboard 1.1.Resource 因为K8S的最小操作单元是Pod,所以这里主要讨论的是Pod的资源 官网:https://kubernetes.io/docs/co ...
- Django class meta
class Main(models.Model): img = models.CharField(max_length=200) # 图片 name = models.CharField(max_le ...
- Markdown学习——Typora入门之常用操作语法及其快捷键
Markdown 学习--Typora入门 Markdown是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档. 由于Markdown的轻 ...
- uni微信小程序优化,多个分包在用的公共代码该放在哪?
公共的代码包括公用的vue组件和js代码,从维护性的角度来说应该放到主包才对, 但是主包有大小限制,如果把2个分包都在用的代码放到主包里面那2M很快就满了. 所以该放在哪?我的方案是从维护的角度放在主 ...
- [源码解析] 模型并行分布式训练Megatron (2) --- 整体架构
[源码解析] 模型并行分布式训练Megatron (2) --- 整体架构 目录 [源码解析] 模型并行分布式训练Megatron (2) --- 整体架构 0x00 摘要 0x01 启动 1.1 分 ...
- Java泛型T与?
感谢大佬:http://m.mamicode.com/info-detail-2657551.html 一.区别 单独的T 代表一个类型 ,而 Class<T>代表这个类型所对应的类, C ...
- Java线程--CompletionService使用
原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11871911.html Java线程--CompletionService使用 public ...
- PHP操作Mysql疑问?
1.Mysql控制台乱码 set character_set_results = 'utf8';