Bash编程(3) 命令行解析与扩展

[email protected]表示脚本输入的全部参数,在bash脚本中,若[email protected]增加引号("[email protected]"),则包含空格的参数也会被保留,若不增加引号([email protected]),则包含空格的参数会被拆分。

例:

# sa脚本内容如下:
pre=:
post=:
printf "$pre%s$post\n" "[email protected]"
#printf "$pre%s$post\n" [email protected]

# 注意[email protected]增加引号和不加引号的区别
$ bash test.sh "a b"
:a b:
#:a:
#:b: 

1. 引号

对于单引号、双引号、转义字符开头的空格,命令行解析时将不会被拆分。

$ sa \ this "is a" ‘demonstration of‘ \  quotes\ and\ espaces ## quotes\ and\ espaces中会转义空格
: this:
:is a:
:demonstration of:
: :
:quotes and espaces:

$ ./sa "a double-quoted single quote, ‘" "a double-quoted double quote, \""  # 单引号中的转义字符将失效,而双引号中的转义将有效
:a double-quoted single quote, ‘:
:a double-quoted double quote, ":

$ ./sa ‘a single-quoted double quotation mark, "‘
:a single-quoted double quotation mark, ":

$ ./sa "First argument "‘still the first argument‘
:First argument still the first argument:

$ echo ‘\‘line1\‘\n\‘line2\‘‘ # 单引号中直接嵌套单引号,会有问题,即使增加转义符也无法正常执行

$ echo $‘\‘line1\‘\n\‘line2\‘‘ # 增加$符号即可解决单引号中嵌套单引号的问题  

2. 花括号

花括号作用于不带引号、以逗号分隔的列表或序列。当作为bash脚本的输入参数时,每个元素作为独立的参数。

$ ./sa {one,two,three}
:one:
:two:
:three:

$ ./sa {1..3} #bash3.0后增加
:1:
:2:
:3:

$ ./sa {a..c}
:a:
:b:
:c:

$ ./sa pre{d,1}date # 花括号前后的字符串将包含在括号中的每个参数中
:preddate:
:pre1date:

$ ./sa {{1..3},{a..c}} # 花括号可以嵌套
:1:
:2:
:3:
:a:
:b:
:c:

$ ./sa {1..3}{a..c} # 连续多个的花括号将会逐个递归扩展
:1a:
:1b:
:1c:
:2a:
:2b:
:2c:
:3a:
:3b:
:3c:

$ ./sa {01..13..3} # 4.0版本的bash具有更高特性:数值序列前缀加0、可以指定序列中的步长
:01:
:04:
:07:
:10:
:13:

$ ./sa {a..h..3} # 也可应用于字母
:a:
:d:
:g: 

3. 波浪号

$ ./sa ~ # 不带引号的~表示当前用户的家目录
:/home/music:

$ ./sa ~root # ~后带用户名,将表示该用户的家目录
:/root:

$ ./sa "~" "~root" # 引号中的~将不会扩展
:~:
:~root:
$ dir=~root
$ dir2="~root"
$ ./sa "$dir" "$dir2"
:/root:
:~root:

$ ./sa ~ws # ~后的用户名若不存在,则不扩展
:~ws:

4. 参数和变量扩展

$ var=whatever
$ ./sa "$var"
:whatever:

$ var=qwerty
$ ./sa "${var}"
:qwerty:

# 通常情况下,{}可选,当位置参数大于9或变量明后紧跟字符时,需要增加{}
$ first=Jane
$ last=Johnson
$ ./sa "$first_$last"  #first_是有效变量名
:Johnson:
$ ./sa "${first}_$last"
:Jane_Johnson: 

5. 算术扩展

$ ./sa "$(( 1 + 12 ))" "$(( 12 * 13 ))" "$(( 16 / 4 ))" "$(( 6 - 9 ))" "$(( 10 % 3 ))"
:13:
:156:
:4:
:-3:
:1:

$ ./sa "$(( 3 + 4 * 5 ))" "$(( (3 + 4) * 5 ))"
:23:
:35:

# 将秒转为天、小时、分钟
secs_in_day=86400
secs_in_hour=3600
mins_in_hour=60
secs_in_min=60

days=$(( $1 / $secs_in_day ))
secs=$(( $1 % $secs_in_day ))

printf "%d:%02d:%02d:%02d\n" "$days" "$(( $secs / $secs_in_hour ))"        "$(( ($secs / $mins_in_hour) % $mins_in_hour ))" "$(( $secs % $secs_in_min ))" 

6. 命令替换

$ wc -l $( date +%Y-%m-%d ).log
1 2019-01-02.log

$ wc -l `date +%Y-%m-%d`.log # ``与$()作用相同
1 2019-01-02.log 

7. 分词

# 单词拆分基于内部字段分隔符(IFS)的值,默认IFS的为s‘ \t\n‘
$ var="this is a multi-word value"
$ ./sa $var "$var"
:this:
:is:
:a:
:multi-word:
:value:
:this is a multi-word value:

# 当IFS具有其默认值或未设置时,任何默认IFS字符序列都将作为单个分隔符读取
$ var=‘ spaced
> out ‘
$ ./sa $var
:spaced:
:out:

# 当IFS包含另一个字符和空格时如" :",该" :"可以拆分字段,但每个分空白字符也可以拆分字段,即":"单独也会进行拆分
$ IFS=‘ :‘
$ var="query : uiop : :: er"
$ ./sa $var
:query:
:uiop:
::
::
:er:

# 当IFS仅包含非空字符时,则IFS中的每个字符拆分字段,且空格将保留
$ IFS=:
$ var="qwery : uiop : :: er"
$ ./sa $var
:qwery :
: uiop :
: :
::
: er: 

8. 路径扩展

# 命令行中若包含*, ?, [,则将被当做文件匹配模式
$ ./sa h*  # 匹配当前路径下以h开头的文件
:hw:
$ ./sa *e  # 匹配当前路径下以k结尾的文件
:datafile:
:errorfile:

$ ./sa ?a* # ?表示仅匹配一个字符
:datafile:
:sa:

# [aceg]表示匹配a,c,e,g中的任意一个
# [h-o]表示匹配h到o中的任意字符
# [[:lower:]]表示匹配小写字母 

9. 进程替换

进程替换将为命令创建一个临时文件。<(commond)使命令的输出像文件名一样可用;>(commond)表示可以写入的文件名。

# totalsize在循环外不可用
$ ls -l |
> while read perms links owner group size month day time file
> do
>     printf "%10d %s\n" "$size" "$file"
>     totalsize=$(( ${totalsize:=0} + ${size:-0} ))
> done
$ echo ${totalsize-unset} ## print "unset" if variable is not set

# 命令替换可以使totalsize在循环外可用
$ while read perms links owner group size month day time file
> do
> printf "%10d %s\n" "$size" "$file"
> totalsize=$(( ${totalsize:=0} + ${size:-0} ))
> done < <(ls -l *)
$ echo ${totalsize-unset}
12879 

10. 解析选项

shell脚本中以-连接的选项,可以使用内置的getops解析。格式为:getopts OPTSTRING var

例:parseopts脚本

progname=${0##*/} ## 获取脚本名称

# 默认值
verbose=0
filename=

# 列出程序接收的选项列表,这些选项带参数,以:连接
optstring=f:v

# while循环调用getopts,直到命令无更多的选项
# 每个选项存储在$opt中,对应的选项参数存储在OPTARG
while getopts $optstring opt
do
    case $opt in
      f) filename=$OPTARG ;; # $OPTARG包含选项对应的参数
      v) verbose=$(( $verbose + 1 )) ;;
      *) exit 1;;
    esac
done

# 命令行中移除选项
## $OPTIND指向下一个,且不解析参数
shift "$(( $OPTIND - 1 ))"

# 检查是否有文件传入
if [ -n "$filename" ]
then
    if [ $verbose -gt 0 ]
    then
        printf "Filename is %s\n" "$filename"
    fi
else
    if [ $verbose -gt 0 ]
    then
        printf "No filename entered\n" >&2
    fi
    exit 1
fi

# 检查文件是否存在
if [ -f "$filename" ]
then
    if [ $verbose -gt 0 ]
    then
        printf "Filename %s found\n" "$filename"
    fi
else
    if [ $verbose -gt 0 ]
    then
       printf "File, %s, does not exist\n" "$filename" >&2
    fi
    exit 2
fi

# 如果选择了verbose选项,打印保留在命令中的数值参数
if [ $verbose -gt 0 ]
then
    printf "Number of arguments is %d\n" "$#"
fi

执行命令结果如下:

$ ./parseopts
$ echo $?
1
$ ./parseopts -v
No filename entered
$ echo $?
1
$ ./parseopts -x
./parseopts: illegal option -- x
$ ./parseopts -vf qwerty
Filename is qwerty
File, qwerty, does not exist
$ ./parseopts -vf qwerty -- -x
Filename is qwerty
File, qwerty, does not exist
$ ./parseopts -vf ~/.bashrc
.bashrc                .bashrc-anaconda3.bak
$ ./parseopts -vf ~/.bashrc -- -x
Filename is /home/music/.bashrc
Filename /home/music/.bashrc found
Number of arguments is 1

原文地址:https://www.cnblogs.com/mengrennwpu/p/10188116.html

时间: 2024-10-09 06:54:30

Bash编程(3) 命令行解析与扩展的相关文章

《学习bash》笔记--命令行处理

shell从标准输入或脚本中读取的每行称为一个管道行,它包含一或多个由0个或多个管道符分割的命令,对其读取的每个管道 行,执行下面的操作. 1.将命令分成由固定元字符集分隔的记号:SPACE.TAB.NEWLINE.;.(.).<.>.|和&.记号类型 包括单词.关键字.I/O重定向符和分号. 2.检测每个命令的第一个记号,查看为不带引号或反斜线的关键字.如果是一个开放的关键字,如if和 其他控制结构起始字符串.function.{或(,则命令实际上为一复合命令.shell在内部对复合

转:python命令行解析工具Argparse

转自:http://www.cnblogs.com/jianboqi/archive/2013/01/10/2854726.html 最近在研究pathon的命令行解析工具,argparse,它是Python标准库中推荐使用的编写命令行程序的工具. 以前老是做UI程序,今天试了下命令行程序,感觉相当好,不用再花大把时间去研究界面问题,尤其是vc++中尤其繁琐. 现在用python来实现命令行,核心计算模块可以用c自己写扩展库,效果挺好. 学习了argparse,在官方文档中找到一篇toturia

python命令行解析工具argparse模块【1】

argpaser是python中很好用的一个命令行解析模块,使用它我们可以很方便的创建用户友好型命令行程序.而且argparse会自动生成帮助信息和错误信息. 一.示例 例如下面的例子,从命令行中获取几个整数,然后获取它们的和或者最大值. import argparse parser = argparse.ArgumentParser(description='Process some integers.') parser.add_argument('integers', metavar='N'

cmdline —— 轻量级的C++命令行解析库

平时用C++写一些命令行工具,需要解析命令行的输入参数,这是一项繁琐并且容易出错的工作,我们不应该将主要精力放在这上面,可以考虑使用开源的库,下面的cmdline就是其中非常好用的一款. cmdline介绍 cmdline 是一个非常简单好用的C++命令行解析库,其基于模板,所以使用很简单,写出的代码也很优雅.由于其只包含一个头文件,所以很容易集成到自己的项目中. cmdline项目托管地址Github:https://github.com/tanakh/cmdline cmdline使用 下面

ZMAN的学习笔记之Python篇:命令行解析

ZMAN的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:ZMAN  (http://www.cnblogs.com/zmanone/) 在Python中,对命令行的解析方式不唯一,本文将介绍两种方法:一种是用sys.argv手动设置,另一种是用argparse模块. 一.sys.argv是什么 首先看一个例子: import sys print(len(sys.argv)) for arg in sys.argv: print(arg) 将

【C++】cmdline —— 轻量级的C++命令行解析库

平时用C++写一些命令行工具,须要解析命令行的输入參数,这是一项繁琐而且easy出错的工作,我们不应该将主要精力放在这上面.能够考虑使用开源的库.以下的cmdline就是当中很好用的一款. cmdline介绍 cmdline 是一个非常easy好用的C++命令行解析库,其基于模板.所以使用非常easy,写出的代码也非常优雅. 因为其仅仅包括一个头文件.所以非常easy集成到自己的项目中. cmdline项目托管地址Github:https://github.com/tanakh/cmdline

docker命令行解析以及如何向服务器端发送请求

最近在看doccker的源码,最新的master分支(估计是1.12.4,因为最新的release是1.12.3)命令行解析全部都使用了第3方的包https://github.com/spf13/cobra.然后看了一下别的分支的代码,感觉结构确实清晰了很多,可读性变高了不少.先看一下如何去使用. 客户端main()在docker/docker/cmd/docker下,可以直接使用go build编译(把vendor下的依赖包移出来就可以了). L20-58: func newDockerCom

python之命令行解析工具argparse

以前写python的时候都会自己在文件开头写一个usgae函数,用来加上各种注释,给用这个脚本的人提供帮助文档. 今天才知道原来python已经有一个自带的命令行解析工具argparse,用了一下,效果还不错. argparse的官方文档请看 https://docs.python.org/2/howto/argparse.html#id1 from argparse import ArgumentParser p = ArgumentParser(usage='it is usage tip'

使用命令行解析php文件

使用命令行解析php文件,这样可以调用Log4PHP库中的一些demo,因为默认的输出使用命令行作为输出. 建一个bat文件: echo 以下是使用命令行解析php文件 C:\xampp\php\php.exe C:\xampp\htdocs\JsonDemo.php pause 直接执行即可.