ABS

    技术2022-05-19  23

     

     

    2.5  引用

     

    2.5.0 引用

    1.重要的作用就是保护命令行中的参数,但还是允许正在调用的程序来扩展它.

    2.可以抑制 echo 命令的换行作用,echo "$(ls -l)"

     

    2.5.1 引用变量

    在一个双引号中直接使用变量名,一般都是没有问题的.它阻止了所有在引号中的特殊字符的

    重新解释--包括变量名[2]--但是$,`和/除外.[3]保留$,作为特殊字符的意义.[4]如果在参

    数列表中使用双引号,将使得双引号中的参数作为一个参数.

     

    5.2 转义(/)

    转义是一种引用单个字符的方法.一个具有特殊含义的字符前边放上一个转义符(/)就告诉shell

    这个字符失去了特殊的含义.

     

    对于特定的转义符的特殊的含义

    在 echo 和sed 中所使用的

    /n 意味着新的一行

    /r 回车

    /t tab 键

    /v vertical tab(垂直tab),查前边的Ctl-K

    /b backspace,查前边的Ctl-H

    /a "alert"(如beep 或flash)

    /0xx 转换成8 进制ASCII 解码,等价于oxx

     

    echo使用-e 选项命令来打印转义符

    echo -e "/v/v/v/v"

     

    使用$'/X'结构,可代替-e 选项

    echo $'/n' # 新行

     

    /" 表达引号本身

    echo "/"Hello/", he said." # "Hello", he said.

     

    /$ 表达$号本身,跟在/$后的变量名,将不能扩展

    echo "/$variable01" # 结果是$variable01

     

    // 表达/号本身.

    echo "//"

     

    转义符也提供续行功能

    echo hello/

    world

     

    2.6 退出和退出状态

     

    exit      #退出

    echo $?   #是否为0

     

    2.7 tests

     

    把[[ $a -lt $b ]]看作一个单独的元素,并且返回一个退出码.

    ((...))和let...结果也能够返回一个退出码

     

    let "1<2" returns 0 (as "1<2" expands to "1")

     

    7.2 文件测试操作

    ----------------

    返回true 如果...

    -e 文件存在

    -a 文件存在

    这个选项的效果与-e 相同.但是它已经被弃用了,并且不鼓励使用

    -f file 是一个regular 文件(不是目录或者设备文件)

    -s 文件长度不为0

    -d 文件是个目录

    -b 文件是个块设备(软盘,cdrom 等等)

    -c 文件是个字符设备(键盘,modem,声卡等等)

    -p 文件是个管道

    -h 文件是个符号链接

    -L 文件是个符号链接

    -S 文件是个socket

    -t 关联到一个终端设备的文件描述符

     

    这个选项一般都用来检测是否在一个给定脚本中的 stdin[-t0]或[-t1]是一个终端

    -r 文件具有读权限(对于用户运行这个test)

    -w 文件具有写权限(对于用户运行这个test)

    -x 文件具有执行权限(对于用户运行这个test)

    -g set-group-id(sgid)标志到文件或目录上

     

    如果一个目录具有 sgid 标志,那么一个被创建在这个目录里的文件,这个目录属于创建

    这个目录的用户组,并不一定与创建这个文件的用户的组相同.对于workgroup 的目录

    共享来说,这非常有用.见<<UNIX 环境高级编程中文版>>第58 页.

     

    -u set-user-id(suid)标志到文件上

    如果运行一个具有 root 权限的文件,那么运行进程将取得root 权限,即使你是一个普通

    用户.[1]这对于需要存取系统硬件的执行操作(比如pppd 和cdrecord)非常有用.如果

    没有 suid 标志的话,那么普通用户(没有root 权限)将无法运行这种程序.

    见<<UNIX 环境高级编程中文版>>第58 页.

     

    -rwsr-xr-t 1 root 178236 Oct 2 2000 /usr/sbin/pppd

    对于设置了 suid 的文件,在它的权限标志中有"s".

    -k 设置粘贴位,见<<UNIX 环境高级编程中文版>>第65 页.

     

    对于"sticky bit",save-text-mode 标志是一个文件权限的特殊类型.如果设置了这

    个标志,那么这个文件将被保存在交换区,为了达到快速存取的目的.如果设置在目录

    中,它将限制写权限.对于设置了sticky bit 位的文件或目录,权限标志中有"t".

     

    drwxrwxrwt 7 root 1024 May 19 21:26 tmp/

    如果一个用户并不时具有 stick bit 位的目录的拥有者,但是具有写权限,那么用户只

    能在这个目录下删除自己所拥有的文件.这将防止用户在一个公开的目录中不慎覆盖

    或者删除别人的文件,比如/tmp(当然root 或者是目录的所有者可以随便删除或重命名

    其中的文件).

     

     

    -O 你是文件的所有者.

    -G 文件的group-id 和你的相同.

    -N 从文件最后被阅读到现在,是否被修改.

     

    f1 -nt f2

    文件 f1 比f2 新

    f1 -ot f2

    f1比f2 老

    f1 -ef f2

    f1和f2 都硬连接到同一个文件.

    ! 非--反转上边测试的结果(如果条件缺席,将返回true)

     

    7.3 其他比较操作

    -------------------

    整数比较

    -eq 等于,如:if [ "$a" -eq "$b" ]

    -ne 不等于,如:if [ "$a" -ne "$b" ]

    -gt 大于,如:if [ "$a" -gt "$b" ]

    -ge 大于等于,如:if [ "$a" -ge "$b" ]

    -lt 小于,如:if [ "$a" -lt "$b" ]

    -le 小于等于,如:if [ "$a" -le "$b" ]

    < 小于(需要双括号),如:(("$a" < "$b"))

    <= 小于等于(需要双括号),如:(("$a" <= "$b"))

    > 大于(需要双括号),如:(("$a" > "$b"))

    >= 大于等于(需要双括号),如:(("$a" >= "$b"))

     

     

    字符串比较

    = 等于,如:if [ "$a" = "$b" ]

    == 等于,如:if [ "$a" == "$b" ],与=等价

    注意:==的功能在[[]]和[]中的行为是不同的,如下:

    1 [[ $a == z* ]] # 如果$a 以"z"开头(模式匹配)那么将为true

    2 [[ $a == "z*" ]] # 如果$a 等于z*(字符匹配),那么结果为true

    3

    4 [ $a == z* ] # File globbing 和word splitting 将会发生

    5 [ "$a" == "z*" ] # 如果$a 等于z*(字符匹配),那么结果为true

     

    关于File globbing 是一种关于文件的速记法,比如"*.c"就是,再如~也是.

    但是 file globbing 并不是严格的正则表达式,虽然绝大多数情况下结构比较像.

     

    != 不等于,如:if [ "$a" != "$b" ]

    这个操作符将在[[]]结构中使用模式匹配.

     

    < 小于,在ASCII 字母顺序下.如:

    if [[ "$a" < "$b" ]]

    if [ "$a" /< "$b" ]

    注意:在[]结构中"<"需要被转义.

     

    > 大于,在ASCII 字母顺序下.如:

    if [[ "$a" > "$b" ]]

    if [ "$a" /> "$b" ]

     

    注意:在[]结构中">"需要被转义.

     

    -z 字符串为"null".就是长度为0.

    -n 字符串不为"null"

     

    注意:

    使用-n 在[]结构中测试必须要用""把变量引起来.使用一个未被""的字符串来使用! -z

    或者就是未用""引用的字符串本身,放到[]结构中(见Example 7-6)虽然一般情况下可

    以工作,但这是不安全的.习惯于使用""来测试字符串是一种好习惯.[1]

     

    算术操作符

    + 加法

    - 减法

    * 乘法

    / 除法

    ** 幂运算

     # Bash, version 2.02, introduced the "**" exponentiation operator.

     let "z=5**3"

     echo "z = $z" # z = 125

     

    % 取模

    bash$ expr 5 % 3

     

    位操作符

    << 左移1 位(每次左移都将乘2)

    <<= 左移几位,=号后边将给出左移几位

    let "var <<= 2"就是左移2 位(就是乘4)

    >> 右移1 位(每次右移都将除2)

    >>= 右移几位

    & 按位与

    &= 按位与赋值

    | 按位或

    |= 按位或赋值

    ~ 按位非

    ! 按位否?

    ^ 按位异或XOR

    ^= 异或赋值

     

    逻辑操作:

    && 逻辑与

    || 逻辑或

     

    混杂操作:

    , 逗号操作符

    逗号操作符可以连接 2 个或多个算术运算.所有的操作都会被执行,但是只有最后一个

    操作作为结果.

    let "t1 = ((5 + 3, 7 - 1, 15 - 4))"

    echo "t1 = $t1" # t1 = 11

     

    数字常量

    shell 脚本默认都是将数字作为10 进制数处理,除非这个数字某种特殊的标记法或前缀开头.

    以0 开头就是8 进制.以0x 开头就是16 进制数.

     

    # 16 进制表示:数字以'0x'或者'0X'开头

     let "hex = 0x32"

     echo "hexadecimal number = $hex" # 50

     # 表达式的结果用10 进制表示.

     

    9 变量重游  

    9.1 内部变量

     

    $BASH

    这个变量将指向 Bash 的二进制执行文件的位置.

    bash$ echo $BASH

    /bin/bash

     

    $BASH_ENV

    这个环境变量将指向一个 Bash 启动文件,这个启动文件将在调用一个脚本时被读取.

     

    $BASH_SUBSHELL

    这个变量将提醒 subshell 的层次,这是一个在version3 才被添加到Bash 中的新特性.

     

    $BASH_VERSINFO[n]

    记录 Bash 安装信息的一个6 元素的数组.与下边的$BASH_VERSION 很像,但这个更加详

    细.

    1 # Bash version info:

    2

    3 for n in 0 1 2 3 4 5

    4 do

    5 echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"

    6 done

    7

    8 # BASH_VERSINFO[0] = 3 # 主版本号

    9 # BASH_VERSINFO[1] = 00 # 次版本号

    10 # BASH_VERSINFO[2] = 14 # Patch 次数.

    11 # BASH_VERSINFO[3] = 1 # Build version.

    12 # BASH_VERSINFO[4] = release # Release status.

    13 # BASH_VERSINFO[5] = i386-redhat-linux-gnu

     

    $BASH_VERSION

    安装在系统上的 Bash 的版本号.

    bash$ echo $BASH_VERSION

    3.00.14(1)-release

    tcsh% echo $BASH_VERSION

    BASH_VERSION: Undefined variable.

    使用这个变量对于判断系统上到底运行的是那个 shll 来说是一种非常好的办法.$SHELL

    有时将不能给出正确的答案.

     

    $DIRSTACK

    在目录栈中最上边的值(将受到pushd 和popd 的影响).

    这个内建的变量与 dirs 命令是保持一致的,但是dirs 命令将显示目录栈的整个内容.

     

    $EDITOR

    脚本调用的默认编辑器,一般是vi 或者是emacs.

     

    $EUID

    "effective"用户ID 号.

    当前用户被假定的任何 id 号.可能在su 命令中使用.

    注意:$EUID 并不一定与$UID 相同.

     

    $FUNCNAME

    当前函数的名字.

    1 xyz23 ()

    2 {

    3 echo "$FUNCNAME now executing." # xyz23 现在正在被执行.

    4 }

    5

    6 xyz23

    7

    8 echo "FUNCNAME = $FUNCNAME" # FUNCNAME =

    9 # 出了函数就变为Null 值了.

     

    $GLOBIGNORE

    一个文件名的模式匹配列表,如果在file globbing 中匹配到的文件包含这个列表中的

    某个文件,那么这个文件将被从匹配到的文件中去掉.

     

    $GROUPS

    当前用户属于的组.

    这是一个当前用户的组 id 列表(数组),就像在/etc/passwd 中记录的一样.

    root# echo $GROUPS

    0

    root# echo ${GROUPS[1]}

    1

    root# echo ${GROUPS[5]}

    6

     

    $HOME

    用户的 home 目录,一般都是/home/username(见Example 9-14)

     

    $HOSTNAME

    hostname 命令将在一个init 脚本中,在启动的时候分配一个系统名字.

    gethostname()函数将用来设置这个$HOSTNAME 内部变量.(见Example 9-14)

     

    $HOSTTYPE

    主机类型

    就像$MACHTYPE,识别系统的硬件.

    bash$ echo $HOSTTYPE

     

    $IGNOREEOF

    忽略 EOF: 告诉shell 在log out 之前要忽略多少文件结束符(control-D).

     

    $LINENO

    这个变量记录它所在的 shell 脚本中它所在行的行号.这个变量一般用于调试目的.

     

    $MACHTYPE

    系统类型

    提示系统硬件

    bash$ echo $MACHTYPE

     

    $PATH

    指向 Bash 外部命令所在的位置,一般为/usr/bin,/usr/X11R6/bin,/usr/local/bin 等.

    当给出一个命令时,Bash 将自动对$PATH 中的目录做一张hash 表.$PATH 中以":"分隔的

    目录列表将被存储在环境变量中.一般的,系统存储的$PATH 定义在/ect/processed 或

    ~/.bashrc.

     

    $PPID

    一个进程的$PPID 就是它的父进程的进程id(pid).[1]

     

    $PROMPT_COMMAND

    这个变量保存一个在主提示符($PS1)显示之前需要执行的命令.

     

    $PWD

    工作目录(你当前所在的目录).

     

    $TMOUT

    如果$TMOUT 环境变量被设置为一个非零的时间值,那么在过了这个指定的时间之后,

    shell提示符将会超时,这会引起一个logout.

     

    $UID

    用户 ID 号.

    当前用户的 id 号,在/etc/passwd 中记录.

    这个值不会因为用户使用了 su 命令而改变.$UID 是只读变量,不容易在命令行或者是脚

    本中被修改,并且和内建的id 命令很相像.

     

     

    位置参数

    $0, $1, $2,等等...

    位置参数,从命令行传递给脚本,或者是传递给函数.或者赋职给一个变量.

     

    $#

    命令行或者是位置参数的个数.

     

    $*

    所有的位置参数,被作为一个单词.

    注意:"$*"必须被""引用.

     

    $@

    与$*同义,但是每个参数都是一个独立的""引用字串,这就意味着参数被完整地传递,

    并没有被解释和扩展.这也意味着,每个参数列表中的每个参数都被当成一个独立的

    单词.

    注意:"$@"必须被引用.

     

    $!

    在后台运行的最后的工作的 PID

     

    $-

    传递给脚本的 falg

     

    9.2 操作字符串

     

    从字符串开始的位置匹配子串的长度

    expr match "$string" '$substring'

    $substring 是一个正则表达式

     

    expr "$string" : '$substring'

    $substring 是一个正则表达式

     

    expr index $string $substring

    匹配到子串的第一个字符的位置

     

    stringZ=abcABC123ABCabc

    echo `expr index "$stringZ" C12  #6

     

    提取子串

    ${string:position}

    在 string 中从位置$position 开始提取子串.

    如果$string 为"*"或"@",那么将提取从位置$position 开始的位置参数,[1]

     

    ${string:position:length}

    在 string 中从位置$position 开始提取$length 长度的子串

     

    ${string:(-position)}

    反向提取子串

     

    expr substr $string $position $length

    在 string 中从位置$position 开始提取$length 长度的子串.

     

    子串削除

    ${string#substring}

    从$string 的左边截掉第一个匹配的$substring

     

    ${string##substring}

    从$string 的左边截掉最后一个个匹配的$substring

     

    9.2.1 awk操作字符串

     

    awk的第一个字符是从'1'开始记录的.

     

    9.4 指定类型的变量:declare 或者typeset

     

    declare/typeset 选项

     

    -r 只读

    declare -r var1

    (declare -r var1与readonly var1 是完全一样的)

     

    -i 整形

    declare -i number

     

    -a 数组

    1 declae -a indices

    变量 indices 将被视为数组

     

    -f 函数

     declare -f

    如果使用 declare -f 而不带参数的话,将会列出这个脚本中之前定义的所有函数.

     declare -f function_name

    如果使用 declare -f function_name 这种形式的话,将只会列出这个函数的名字

     

    -x export

     declare -x var3

    这种使用方式,将会把var3 export 出来.

     

    9.5 变量的间接引用

     使用符号:eval var1=/$$var2.

     

    9.6 $RANDOM: 产生随机整数

    $RANDOM 是Bash 的内部函数(并不是常量),这个函数将返回一个范围在0 - 32767 之间的一个伪

    随机整数.它不应该被用来产生密匙.

     

    9.7 双圆括号结构

    ((...))与let 命令很像,允许算术扩展和赋值.举个简单的例子a=$(( 5 + 3 )),将把a 设为

    "5+3"或者8.然而,双圆括号也是一种在Bash 中允许使用C 风格的变量处理的机制

     

    [未完]


    最新回复(0)