陈斌彬的技术博客

Stay foolish,stay hungry

Bash - 引用变量

一、引用变量

1.介绍

在一个双引号中通过直接使用变量名的方法来引用变量,一般情况下都是没问题的。这么做将阻止所有在引号中的特殊字符被重新解释(即都被当作普通的字符串),包括变量名,但是 $、`(后置引用)和 “\"(转义符)除外。

保留 $ 作为特殊字符的意义是为了能够在双引号中也能够正常的引用变量("$variable")。

使用双引号还能够阻止单词分割,即使这个参数包含有空白,单词也不会被分隔开。 如 variable1=“a variable containing five words”

2.举例

在 echo 语句中,只有在单词分割或者需要保留空白的时候,才需要把参数用双引号括起来。

$ vim test.sh

输入代码:

#!/bin/bash

var="'(]\\{}\$\""
echo $var        # '(]\{}$"
echo "$var"      # '(]\{}$"     #同上

echo

IFS='\'
echo $var        # '(] {}$"     \ 字符被空白符替换了, 为什么?
echo "$var"      # '(]\{}$"
echo '$var'      # $var

exit 0

IFS (Internal Field Seperator) 在 Linux 的 shell 中预设的分隔符。IFS 是 shell 脚本中的一个重要概念,在处理文本数据时,它是相当有用的。内部字段分隔符是用于特定用途的定界符。IFS 是存储定界符的环境变量,它是当前 shell 环境使用的默认定界字符串。

当我们设置了 bash 内置变量 IFS 后,再使用 echo 输出时,会将所设定的字符用空格去代替。

运行代码:

$ bash test.sh

单引号(' ') 操作与双引号基本一样,但是不允许引用变量,因为 $ 的特殊意义将被关闭。

在单引号中,任何特殊字符都按照字面的意思进行解释,除了单引号本身。所以说单引号(全引用)是一种比双引号(部分引用)更严格的引用方法。

二、转义

1.概念

转义是一种引用单个字符的方法。一个前面放上转义符 (\) 的字符就是告诉 shell 这个字符按照字面的意思进行解释,换句话说,就是这个字符失去了它的特殊含义。

2.转义符的含义

在 echo 命令中:

符号 说明 * \n 表示新的一行 * \r 表示回车 * \t 表示水平制表符 * \v 表示垂直制表符 * \b 表示后退符 * \a 表示"alert"(蜂鸣或者闪烁) * \0xx 转换为八进制的ASCII码, 等价于0xx\“ 表示引号字面的意思,如:

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

\$ 表示 $ 本身字面的含义(跟在 \$ 后边的变量名将不能引用变量的值),如:

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

\\ 表示反斜线字面的意思,如:

$ echo "\\"  # 结果是 \

3.一个实例

$ vim test.sh

输入代码:

#!/bin/bash

echo "\v\v\v\v"      # 逐字的打印\v\v\v\v.
# 使用-e选项的'echo'命令来打印转义符.
echo "============="
echo "VERTICAL TABS"
echo -e "\v\v\v\v"   # 打印4个垂直制表符.
echo "=============="

echo "QUOTATION MARK"
echo -e "\042"       # 打印" (引号, 8进制的ASCII 码就是42).
echo "=============="

# 如果使用$'\X'结构,那-e选项就不必要了.
echo; echo "NEWLINE AND BEEP"
echo $'\n'           # 新行.
echo $'\a'           # 警告(蜂鸣).

echo "==============="
echo "QUOTATION MARKS"
# 版本2以后Bash允许使用$'\nnn'结构.
# 注意在这里, '\nnn\'是8进制的值.
echo $'\t \042 \t'   # 被水平制表符括起来的引号(").

# 当然,也可以使用16进制的值,使用$'\xhhh' 结构.
echo $'\t \x22 \t'  # 被水平制表符括起来的引号(").
# 感谢, Greg Keraunen, 指出了这点.
# 早一点的Bash版本允许'\x022'这种形式.
echo "==============="
echo


# 分配ASCII字符到变量中.
# ----------------------------------------
quote=$'\042'        # " 被赋值到变量中.
echo "$quote This is a quoted string, $quote and this lies outside the quotes."

echo

# 变量中的连续的ASCII字符.
triple_underline=$'\137\137\137'  # 137是八进制的'_'.
echo "$triple_underline UNDERLINE $triple_underline"

echo

ABC=$'\101\102\103\010'           # 101, 102, 103是八进制码的A, B, C.
echo $ABC

echo; echo

escape=$'\033'                    # 033 是八进制码的esc.
echo "\"escape\" echoes as $escape"
#                                   没有变量被输出.

echo; echo

exit 0

其中 echo 的 -e 参数表示使能反斜线转义

运行代码:

$ bash test.sh

4.转义符(\)的行为探究

\ 的行为依赖于它自身是否被转义,被引用 ("") ,或者是否出现在命令替换或 here document 中。

$ vim test.sh

输入代码:

#!/bin/bash
                   #  简单的转义和引用
echo \z               #  z
echo \\z              # \z
echo '\z'             # \z
echo '\\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

运行代码:

$ bash test.sh

5.变量中的转义

赋值给变量的字符串的元素也会被转义,但是不能把一个单独的转义符赋值给变量。

$ vim test.sh

输入代码:

 #!/bin/bash

 variable=\
 echo "$variable"
 # 不能正常运行 - 会报错:
 # test.sh: : command not found
 # 一个"裸体的"转义符是不能够安全的赋值给变量的.
 #
 #  事实上在这里"\"转义了一个换行符(变成了续航符的含义), 
 #+ 效果就是                variable=echo "$variable"
 #+                      不可用的变量赋值

 variable=\
 23skidoo
 echo "$variable"        #  23skidoo
                         #  这句是可以的, 因为
                         #+ 第2行是一个可用的变量赋值.

 variable=\ 
 #             \^    转义一个空格
 echo "$variable"        # 显示空格

 variable=\\
 echo "$variable"        # \

 variable=\\\
 echo "$variable"
 # 不能正常运行 - 报错:
 # test.sh: \: command not found
 #
 #  第一个转义符把第2个\转义了,但是第3个又变成"裸体的"了,
 #+ 与上边的例子的原因相同.

 variable=\\\\
 echo "$variable"        # \\
                         # 第2和第4个反斜线被转义了.
                         # 这是正确的.

运行代码:

$ bash test.sh

6.转义空格

转义一个空格会阻止命令行参数列表的“单词分割”问题。

$ vim test.sh

输入代码:

#!/bin/bash

file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
# 列出的文件都作为命令的参数.

# 加两个文件到参数列表中, 列出所有的文件信息.
ls -l /usr/lib/gconv /usr $file_list

echo "-------------------------------------------------------------------------"

# 如果我们将上边的两个空个转义了会产生什么效果?
ls -l /usr/lib/gconv\ /usr\ $file_list
# 错误: 因为前3个路径被合并成一个参数传递给了'ls -l'
#       而且两个经过转义的空格组织了参数(单词)分割.

运行代码:

$ bash test.sh

7.续行功能

转义符也提供续行功能,也就是编写多行命令的功能。

每一个单独行都包含一个不同的命令,但是每行结尾的转义符都会转义换行符,这样下一行会与上一行一起形成一个命令序列。

$ vim test.sh

输入代码:

#!/bin/bash

mkdir ~/source
mkdir ~/dest
touch ~/source/s.tar

(cd ~/source && tar cf - . ) | \
(cd ~/dest && tar xpvf -)
# 重复Alan Cox的目录数拷贝命令,
# 但是分成两行是为了增加可读性.

# 也可以使用如下方式:
# tar cf - -C ~/source/ . |
# tar xpvf - -C ~/dest/

运行代码:

$ bash test.sh

如果一个脚本以 | (管道符)结束,那么就不用非的加上转义符 (\) 了。但是一个好的编程风格,还是应该在行尾加上转义符。