美文网首页
Shell基础脚本-引用

Shell基础脚本-引用

作者: Chris0Yang | 来源:发表于2021-11-14 20:49 被阅读0次

    引用就是将一个字符串用引号括起来。这样做是为了保护Shell/Shell脚本中被重新解释过或带扩展功能的特殊字符(如果一个字符带有其特殊意义而不仅仅是字面量的话,这个字符就能称为“特殊字符”。比如星号“*”就能表示 正则表达式 中的一个通配符

    bash$ ls -l [Vv]*
    -rw-rw-r--    1 bozo  bozo       324 Apr  2 15:05 VIEWDATA.BAT
    -rw-rw-r--    1 bozo  bozo       507 May  4 14:25 vartrace.sh
    -rw-rw-r--    1 bozo  bozo       539 Apr 14 17:11 viewdata.sh
    
    bash$ ls -l '[Vv]*'
    ls: [Vv]*: No such file or directory
    
    可以看到,提示不存在该文件。
    这里的'[Vv]*被当成了文件名。 
    在日常沟通和写作中,当我们引用一个短语的时候,我们会将它单独隔开并赋予它特殊的意义
    而在bash脚本中,当我们引用一个字符串,意味着保留它的字面量。
    

    很多程序和公用代码会展开被引用字符串中的特殊字符。
    引用的一个重用用途是保护Shell中的命令行参数,但仍然允许调用的程序扩展它

    bash$ grep '[Ff]irst' *.txt
    file1.txt:This is the first line of file1.txt.
    file2.txt:This is the First line of file2.txt.
    

    在所有.txt文件中找出包含first或者First字符串的行

    注意,不加引号的 grep [Ff]irst *.txt 在Bash下也同样有效

    引用也可以控制echo命令的断行符

    bash$ echo $(ls -l)
    total 8 -rw-rw-r-- 1 bo bo 13 Aug 21 12:57 t.sh -rw-rw-r-- 1 bo bo 78 Aug 21 12:57 u.sh
    
    
    bash$ echo "$(ls -l)"
    total 8
     -rw-rw-r--  1 bo bo  13 Aug 21 12:57 t.sh
     -rw-rw-r--  1 bo bo  78 Aug 21 12:57 u.sh
    

    1、引用变量

    引用变量时,通常建议将变量包含在双引号中。
    因为这样可以防止除 $,` (反引号)和\(转义符)之外的其他特殊字符被重新解释。
    在双引号中仍然可以使用$引用变量("$variable"),也就是将变量名替换为变量值
    使用双引号可以防止字符串被分割
    即使参数中拥有很多空白分隔符,被包在双引号中后依旧是算作单一字符。
    
    List="one two three"
    
    for a in $List     # 空白符将变量分成几个部分。
    do
      echo "$a"
    done
    # one
    # two
    # three
    
    echo "---"
    
    for a in "$List"   # 在单一变量中保留所有空格。
    do #     ^     ^
      echo "$a"
    done
    # one two three 
    

    下面是一个更加复杂的例子:

    variable1="a variable containing five words"
    COMMAND This is $variable1    # 带上7个参数执行COMMAND命令:
    # "This" "is" "a" "variable" "containing" "five" "words"
    
    COMMAND "This is $variable1"  # 带上1个参数执行COMMAND命令:
    # "This is a variable containing five words"
    
    
    variable2=""    # 空值。
    
    COMMAND  $variable2 $variable2 $variable2
                    # 不带参数执行COMMAND命令。
    COMMAND "$variable2" "$variable2" "$variable2"
                    # 带上3个参数执行COMMAND命令。
    COMMAND "$variable2 $variable2 $variable2"
                    # 带上1个参数执行COMMAND命令(2空格)。
    

    当字符分割或者保留空白符出现问题时,才需要在echo语句中用双引号包住参数

    样例-1. 输出一些奇怪的变量

    #!/bin/bash
    # weirdvars.sh: 输出一些奇怪的变量
    
    echo
    
    var="'(]\\{}\$\""
    echo $var        # '(]\{}$"
    echo "$var"      # '(]\{}$"     没有任何区别。
    
    echo
    
    IFS='\'
    echo $var        # '(] {}$"     \ 被转换成了空格,为什么?
    echo "$var"      # '(]\{}$"
    
    # 上面的例子由 Stephane Chazelas 提供。
    
    echo
    
    var2="\\\\\""
    echo $var2       #   "
    echo "$var2"     # \\"
    echo
    # 但是...var2="\\\\"" 不是合法的语句,为什么?
    var3='\\\\'
    echo "$var3"     # \\\\
    # 强引用是可以的。
    
    
    # ************************************************************ #
    # 就像第一个例子展示的那样,嵌套引用是允许的。
    
    echo "$(echo '"')"           # "
    #    ^           ^
    
    
    # 在有些时候这种方法非常有用。
    
    var1="Two bits"
    echo "\$var1 = "$var1""      # $var1 = Two bits
    #    ^                ^
    
    # 或者,可以像 Chris Hiestand 指出的那样:
    
    if [[ "$(du "$My_File1")" -gt "$(du "$My_File2")" ]]
    #     ^     ^         ^ ^     ^     ^         ^ ^
    then
      ...
    fi
    # ************************************************************ #
    

    单引号(' ')与双引号类似,但是在单引号中不能引用变量,因为 $ 不再具有特殊含义
    在单引号中,除'之外的所有特殊字符都将会被直接按照字面意思解释,可以认为单引号(“全引用”)是双引号(“部分引用”)的一种更严格的形式

    因为在单引号中转义符(\)都已经按照字面意思解释了
    因此尝试在单引号中包含单引号将不会产生你所预期的结果
    
    echo "Why can't I write 's between single quotes"
    
    echo
    
    # 可以采取迂回的方式。
    echo 'Why can'\''t I write '"'"'s between single quotes'
    #    |-------|  |----------|   |-----------------------|
    # 由三个单引号引用的字符串,再加上转义以及双引号包住的单引号组成。
    

    2、转义

    转义是一种引用单字符的方法。通过在特殊字符前加上转义符 \ 来告诉shell按照字面意思去解释这个字符

    需要注意的是,在一些特定的命令和工具
    比如: echo 和 sed 中,转义字符通常会起到相反的效果,即可能会使得那些字符产生特殊含义
    

    在 echo 与 sed 命令中,转义字符的特殊含义

    ( \n )

    换行(line feed)

    ( \r )

    回车(carriage return)

    ( \t )

    水平制表符

    ( \v )

    垂直制表符

    ( \b )

    退格

    ( \a )

    警报、响铃或闪烁

    ( \0xx )

    ASCII码的八进制形式,等价于 0nn,其中 nn 是数字

    在 $' ... ' 字符串扩展结构中可以通过转义八进制或十六进制的ASCII码形式给变量赋值
    比如: quote=$'\042'
    

    样例-2. 转义字符

    #!/bin/bash
    # escaped.sh: 转义字符
    
    ##############################################
    ### 首先让我们先看一下转义字符的基本用法。 ###
    ##############################################
    
    # 转义新的一行。
    # ------------
    
    echo ""
    
    echo "This will print
    as two lines."
    # This will print
    # as two lines.
    
    echo "This will print \
    as one line."
    # This will print as one line.
    
    echo; echo
    
    echo "============="
    
    
    echo "\v\v\v\v"      # 按字面意思打印 \v\v\v\v
    # 使用 echo 命令的 -e 选项来打印转义字符。
    echo "============="
    echo "VERTICAL TABS"
    echo -e "\v\v\v\v"   # 打印四个垂直制表符。
    echo "=============="
    
    echo "QUOTATION MARK"
    echo -e "\042"       # 打印 " (引号,八进制ASCII码为42)。
    echo "=============="
    
    
    
    # 使用 $'\X' 这样的形式后可以不需要加 -e 选项。
    
    echo; echo "NEWLINE and (maybe) BEEP"
    echo $'\n'           # 新的一行。
    echo $'\a'           # 警报(响铃)。
                         # 根据不同的终端版本,也可能是闪屏。
    
    # 我们之前介绍了 $'\nnn' 字符串扩展,而现在我们要看到的是...
    
    # ============================================ #
    # 自 Bash 第二个版本开始的 $'\nnn' 字符串扩展结构。
    # ============================================ #
    
    echo "Introducing the \$\' ... \' string-expansion construct . . . "
    echo ". . . featuring more quotation marks."
    
    echo $'\t \042 \t'   # 在制表符之间的引号。
    # 需要注意的是 '\nnn' 是一个八进制的值。
    
    # 字符串扩展同样适用于十六进制的值,格式是 $'\xhhh'。
    echo $'\t \x22 \t'  # 在制表符之间的引号。
    # 感谢 Greg Keraunen 指出这些。
    # 在早期的 Bash 版本中允许使用 '\x022' 这样的形式。
    
    echo
    
    
    # 将 ASCII 码字符赋值给变量。
    # -----------------------
    quote=$'\042'        # 将 " 赋值给变量。
    echo "$quote Quoted string $quote and this lies outside the quotes."
    
    echo
    
    # 连接多个 ASCII 码字符给变量。
    triple_underline=$'\137\137\137'  # 137是 '_' ASCII码的八进制形式
    echo "$triple_underline UNDERLINE $triple_underline"
    
    echo
    
    ABC=$'\101\102\103\010'           # 101,102,103是 A, B, C 
                                      # ASCII码的八进制形式。
    echo $ABC
    
    echo
    
    escape=$'\033'                    # 033 是 ESC 的八进制形式
    echo "\"escape\" echoes an $escape"
                                      # 没有可见输出
    
    echo
    
    exit 0
    

    下面是一个更加复杂的例子:
    样例-3. 检测键盘输入

    #!/bin/bash
    # 需要 Bash 版本高于4.2。
    
    key="no value yet"
    while true; do
      clear
      echo "Bash Extra Keys Demo. Keys to try:"
      echo
      echo "* Insert, Delete, Home, End, Page_Up and Page_Down"
      echo "* The four arrow keys"
      echo "* Tab, enter, escape, and space key"
      echo "* The letter and number keys, etc."
      echo
      echo "    d = show date/time"
      echo "    q = quit"
      echo "================================"
      echo
    
      # 将独立的Home键值转换为数字7上的Home键值:
      if [ "$key" = $'\x1b\x4f\x48' ]; then
       key=$'\x1b\x5b\x31\x7e'
       #   引用字符扩展结构。
      fi
    
      # 将独立的End键值转换为数字1上的End键值:
      if [ "$key" = $'\x1b\x4f\x46' ]; then
       key=$'\x1b\x5b\x34\x7e'
      fi
    
      case "$key" in
       $'\x1b\x5b\x32\x7e')  # 插入
        echo Insert Key
       ;;
       $'\x1b\x5b\x33\x7e')  # 删除
        echo Delete Key
       ;;
       $'\x1b\x5b\x31\x7e')  # 数字7上的Home键
        echo Home Key
       ;;
       $'\x1b\x5b\x34\x7e')  # 数字1上的End键
        echo End Key
       ;;
       $'\x1b\x5b\x35\x7e')  # 上翻页
        echo Page_Up
       ;;
       $'\x1b\x5b\x36\x7e')  # 下翻页
        echo Page_Down
       ;;
       $'\x1b\x5b\x41')  # 上箭头
        echo Up arrow
       ;;
       $'\x1b\x5b\x42')  # 下箭头
        echo Down arrow
       ;;
       $'\x1b\x5b\x43')  # 右箭头
        echo Right arrow
       ;;
       $'\x1b\x5b\x44')  # 左箭头
        echo Left arrow
       ;;
       $'\x09')  # 制表符
        echo Tab Key
       ;;
       $'\x0a')  # 回车
        echo Enter Key
       ;;
       $'\x1b')  # ESC
        echo Escape Key
       ;;
       $'\x20')  # 空格
        echo Space Key
       ;;
       d)
        date
       ;;
       q)
        echo Time to quit...
        echo
        exit 0
       ;;
       *)
        echo Your pressed: \'"$key"\'
       ;;
      esac
    
      echo
      echo "================================"
    
      unset K1 K2 K3
      read -s -N1 -p "Press a key: "
      K1="$REPLY"
      read -s -N2 -t 0.001
      K2="$REPLY"
      read -s -N1 -t 0.001
      K3="$REPLY"
      key="$K1$K2$K3"
    
    done
    
    exit $?
    

    ( " )

    转义引号,指代自身

    echo "Hello"                     # Hello
    echo "\"Hello\" ... he said."    # "Hello" ... he said.
    

    ( $ )

    转义美元符号(跟在 \$ 后的变量名将不会被引用)

    echo "\$variable01"           # $variable01
    echo "The book cost \$7.98."  # The book cost $7.98.
    

    ( \ )

    转义反斜杠,指代自身

    echo "\\"  # 结果是 \
    
    # 然而...
    
    echo "\"   # 在命令行中会出现第二行并提示输入。
               # 在脚本中会出错。
    
    # 但是...
    
    echo '\'   # 结果是 \
    
    根据转义符所在的上下文(强引用、弱引用,命令替换或者在 here document)的不同
    它的行为也会有所不同
    
                          #  简单转义与引用
    echo \z               #  z
    echo \\z              # \z
    echo '\z'             # \z
    ehco '\\z'            # \\z
    echo "\z"             # \z
    echo "\\z"            # \z
    
                          #  命令替换
    echo `echo \z`        #  z
    echo `echo \\z`       #  z
    echo `echo \\\z`      # \z
    echo `echo \\\\z`     # \z
    echo `echo \\\\\\z`   # \z
    echo `echo \\\\\\\z`  # \\z
    echo `echo "\z"`      # \z
    echo `echo "\\z"`     # \z
    
                          # Here Document
    cat <<EOF
    \z
    EOF                   # \z
    
    cat <<EOF
    \\z
    EOF                   # \z
    

    含有转义字符的字符串可以赋值给变量,但是仅仅将单一的转义符赋值给变量是不可行的

    variable=\
    echo "$variable"
    # 这样做会报如下错误:
    # tesh.sh: : command not found
    # 单独的转义符不能够赋值给变量。
    # 
    #  事实上,"\" 转义了换行,实际效果是:
    #+ variable=echo "$variable"
    #+ 这是一个非法的赋值方式。
    
    variable=\
    23skidoo
    echo "$variable"        # 23skidoo
                            # 因为第二行是一个合法的赋值,因此不会报错。
    
    variable=\ 
    #        \^    转义符后有一个空格
    echo "$variable"        # 空格
    
    variable=\\
    echo "$variable"        # \
    
    variable=\\\
    echo "$variable"
    # 这样做会报如下错误:
    # tesh.sh: \: command not found
    #
    #  第一个转义符转转义了第二个,但是第三个转义符仍旧转义的是换行,
    #+ 跟开始的那个例子一样,因此会报错。
    
    variable=\\\\
    echo "$variable"        # \\
                            # 第二个和第四个转义符被转义了,因此可行。
    

    转义空格能够避免在命令参数列表中的字符分割问题

    file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
    # 将一系列文件作为命令的参数。
    
    # 增加两个文件到列表中,并且列出整个表。
    ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
    
    echo "-------------------------------------------------------------------------"
    
    # 如果我们转义了这些空格会怎样?
    ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
    # 错误:因为转义了两个空格,因此前三个文件被连接成了一个参数传递给了 'ls -l'
    

    转义符也提供一种可以撰写多行命令的方式。通常,每一行是一个命令,但是转义换行后命令就可以在下一行继续撰写

    (cd /source/directory && tar cf - . ) | \
    (cd /dest/directory && tar xpvf -)
    # 回顾 Alan Cox 的目录树拷贝命令,但是把它拆成了两行。
    
    # 或者你也可以:
    tar cf - -C /source/directory . |
    tar xpvf - -C /dest/directory
    
    在脚本中,如果以 "|" 管道作为一行的结束字符,那么不需要加转义符  也可以写多行命令。
    但是一个好的编程习惯就是在写多行命令的事后,无论什么情况都要在行尾加上转义符 \
    
    echo "foo
    bar"
    #foo
    #bar
    
    echo
    
    echo 'foo
    bar'    # 没有区别。
    #foo
    #bar
    
    echo
    
    echo foo\
    bar     # 转义换行。
    #foobar
    
    echo
    
    echo "foo\
    bar"     # 没有区别,在弱引用中,\ 转义符仍旧转义了换行。
    #foobar
    
    echo
    
    echo 'foo\
    bar'     # 在强引用中,\ 就按照字面意思来解释了。
    #foo\
    #bar
    

    相关文章

      网友评论

          本文标题:Shell基础脚本-引用

          本文链接:https://www.haomeiwen.com/subject/soqxtrtx.html