烦恼一般都是想太多了。

0%

Bash编程参考-参数与扩展

通过参考bash手册,详细的总结了其特殊参数,已经进行扩展的方式。

引用

引用的目的是去除某些字符或单词的特殊含义。可以用来禁止对特殊字符的特殊处理,使保留字不再是保留字,或者禁止参数扩展。其有三种方式进行引用。

  • \ 转义字符,其后的字符具有字面意义。当其后跟随一个\newline时,将会忽略这个换行,。
  • ' 单引号 所有单引号间的字符具有字面意义。' some char'间不能再出现',即使是被转义的。
  • " 双引号 所有双引号间的字符具有字面意义,除了$$`、!(如果开启了历史扩展)$$、‘`保留其特殊功能;反斜杠\只有其后面是\$'"newline才保留转义功能,不然表示的是它自己;如果\后的字符并没有什么特殊意义,那么\就会被保留;@*具有特殊意义。

    shell 参数

    当你以 NAME=[VALUE] 形式的时候,你就定义了一个变量NAME,其值是VALUE(空字符串是允许的),你可以通过 unset命令取消这个变量。
    变量VALUE会进行大括号扩展、参数和变量扩展、命令替换、算数扩展、以及引用去除

    位置参数(Positional Parameters)

    位置参数说的就是命令行的参数,如下命令行:
    ./test.sh one two three
    其具有位置参数$1, $2, $3 one, two, three** 。第N个参数可以表示为$N ,但是当参数大于等于10的时候,就必须用*${N} 来表示。
    位置参数不能进行赋值,只能通过setshift(左移位置参数)来设置或删除。

特殊参数(如上例)

  • $* 等价于 “$1 $2 $3”
  • $@ 等价于 “$1” “$2” “$3”

    $* $@只有在用 “”包围起来引用的时候才有区别,否则看起来他们是一样的。

  • $# 参数个数
  • $? 退出状态
  • $- 验证shell是不是交互式的 Linux利用Cron定时任务编写脚本的注意
  • $$ 进程号。子shell() 中的时候,扩展为当前进程号而不是子shell进程号。
  • $! 最近在后台执行的命令退出状态。
  • $0 执行脚本名称
  • $_ 启动时,设置为启动shell的绝对路径,或者在执行环境或参数列表中所传递的待执行的shell脚本的绝对路径。随后,扩展为上一条命令的最后一个参数扩展后的值。还可设为每个已执行命令的绝对路径,这些路径是启动时指定的并且导入到命令的执行环境中。

    shell 扩展

    命令行被拆分成符号后要进行扩展,有七种方式:
  • 大括号扩展 { }
  • 波浪号扩展 ~引导
  • 参数和变量扩展 $引导
  • 命令替换 $( )或
  • 算数扩展 $(( ))
  • 单词拆分
  • 文件名扩展
    扩展顺序为:大括号扩展、波浪号扩展、参数、变量和算术扩展、命令替换、单词拆分、文件名扩展。

    大括号扩展

    echo a{a..z}{1..10}b
    echo a{a,b,c,d}b

波浪号(~)

  • ~ $HOME的值
  • ~fred/foo 用户fred家目录下的foo目录

    还有更多表示法,但是感觉不常用,所以没有进行说明。阅读的话参考手册

参数、变量扩展

基本形式${ARG}。用以引导参数扩展、命令替换、算数扩展
以下的几种情况中,WORD要进行波浪号扩展、参数扩展、命令替换和算数扩展。也就说,WORD可以是:一个字符串、一个带波浪号的路径、一个变量、一串命令、一个算术表达式
当不是进行字符扩展的时候,Bash测试ARG是否未设置或者为空;如果忽略了冒号,则只测试值是否设置。

  • ${ARG:-WORD} 如果就ARG没有设置或者为null,就扩展为WORD的值。
  • ${ARG:=WORD} 如果就ARG没有设置或者为null,扩展WORD值给ARG(ARG就会被设置)。位置参数和特殊参数不能这样操作。
  • ${ARG:?WORD} 如果就ARG没有设置或者为null,扩展WORD的值(如果没有设置WORD,给出意义差不多的信息)然后写到标准错误和shell,如果是在非交互模式下,退出shell。
  • ${ARG:+WORD} 如果就ARG没有设置或者为null,什么都不做。否则,就用WORD进行扩展。
  • ${ARG:OFFSET[:LENGTH]} 从ARG的OFFSET位置截取LENGTH个字符,LENGTH必须大于等于0。
    如果OFFSET小于0,那么就是从ARG值的结尾开始的偏移量(注意:-号间要有一个空格)
    如果ARG是@,那么就是从第OFFSET第LENGTH个位置参数。
    如果ARG是以数组ARG[@]或ARG[*],那么就是从第OFFSET位置开始的LENGTH个成员。
    除了位置参数的索引位置是从1开始外,字符串和数组都是从0开始的。
  • ${!PREFIX*} ${PREFIX@}
  • ${!NAME[@]} $[!NAME[*]}
  • ${#ARG} 返回${ARG}的长度。如果ARG是@或*,那么返回位置参数的个数。如果是数组ARG[@]或ARG[*],那么返回元素个数。
  • ${ARG#WORD}
    ${ARG##WORD} 删除WORD模式从开始位置匹配的字符。WORD被扩展为一个模式,就跟文件名扩展一样。如果WORD模式与ARG扩展后的值开始部分匹配,那么#是最短匹配,##是最长匹配,然后删除匹配的字符。
    如果参数是#或*,扩展后得到的是位置参数列表。
    如果参数是带有下标#或*的数组,那么得到的是元素列表。
  • ${ARG%WORD} ${ARG%%WORD} 删除WORD模式从最后位置匹配的字符。WORD被扩展为一个模式,就跟文件名扩展一样。如果WORD模式与ARG扩展后的值结束部分匹配,那么%是最短匹配,%是最长匹配,然后删除匹配的字符。
    如果参数是#或*,扩展后得到的是位置参数列表。
    如果参数是带有下标#或*的数组,那么得到的是元素列表。
  • ${ARG/PATTERN/STRING} PATTERN产生一个类似文件名扩展的模式。将ARG的值扩展后最长匹配部分用STRING进行替换。
    如果PATTERN以/开始,那么所有匹配都会进行替换。
    如果PATTERN以#开始,那么从开始位置进行匹配。
    如果PATTERN以%开始,那么从结尾部分开始匹配。
    同样可以操作数组ary[*]或ary[@]

    命令替换

    命令替换的形式类似
    ( command )  
    `command`

其结果是命令的输出,并删除行尾换行符。
命令替换形式$(cat filename)可以用效果等价但是速度更快的$(< filename) 来替代。
如果使用第二种格式,也就是使用了反引号。\保留其本身含义,除非其后面的是$、`或\
如果是$( command )中的所有字符组成命令,不会被特殊处理。

算术扩展

算术替换类似

$(( expr ))

进程替换

如果系统支持FIFO或以/dev/fd/N方式来命名打开的文件,就支持进程替换,基本格式是:

<(LIST) or >(LIST)

注意:如果><(LIST)间有空格,则被认为是重定向。

这样进程 LIST运行时就会将其输入或输出与一个FIFO或文件/dev/fd/N相连接。
例:

ls -l <(echo test)
cat <(echo test)

这样就了解echo test的输出与一个文件相关联,然后ll就去读取这个文件。执行一下看输出:

lr-x——— 1 root root 64 12-09 09:52 /dev/fd/63 -> pipe:[2215427]
test

单词拆分

shell会把扩展后的输入根据分割符IFS拆分一个个单词。用""''明确指定的空白会进行保留。

文件名扩展

单词拆分以后,shell会在每个单词内搜索字符*?[,除非打开了*-f选项。如果找到其中一个,就这个单词当作一个模式,并把与其匹配的文件名进行按字母排序来取代它。

  • * 匹配任何字符,包括空白。
  • ? 匹配单个字符。
  • […] 匹配方括号中的任一字符。还可以用[:type:]的POSIX形式来匹配。
    alnum 字母跟数字
    alpha 字母
    acsii 所有ASCII字符
    blank 所有空白字符
    cntrl 所有控制字符(ASCII中的20个字符)
    digit 数字
    graph 可显示字符(可打印,空格、退格无法显示)
    lower 小写字母
    print 可打印字符(非控制字符)
    punct 标点符号
    space 空格
    uperr 大写字母
    word 匹配单词里的字符(大小写字母、数字、下划线)
    xdigit 10进制字符(0-9 A-F)