Bash 只有一种数据类型,就是字符串。不管用户输入什么数据,Bash 都视为字符串。因此,字符串相关的引号和转义,对 Bash 来说就非常重要。
某些字符在 Bash 里面有特殊含义(比如$
、&
、*
),如果想要原样输出这些特殊字符,就必须在它们前面加上反斜杠,使其变成普通字符。这就叫做“转义”(escape)。
比如:
1 | # 只有在特殊字符`$`前面加反斜杠,才能原样输出。否则会输出date变量的值 |
反斜杠除了用于转义,还可以表示一些不可打印的字符。
\a
:响铃\b
:退格\n
:换行\r
:回车\t
:制表符如果想要在命令行使用这些不可打印的字符,可以把它们放在引号里面,然后使用echo
命令的-e
参数。
1 | $ echo a\tb |
换行符是一个特殊字符,表示命令的结束,Bash 收到这个字符以后,就会对输入的命令进行解释执行。换行符前面加上反斜杠转义,就使得换行符变成一个普通字符,Bash 会将其当作长度为0
的空字符处理,从而可以将一行命令写成多行。
1 | # 如果一条命令过长,就可以在行尾使用反斜杠,将其改写成多行。这是常见的多行命令的写法 |
Bash 允许字符串放在单引号或双引号之中,加以引用。
单引号用于保留字符的字面含义,各种特殊字符在单引号里面,都会变为普通字符,比如星号(*
)、美元符号($
)、反斜杠(\
)等。
1 | # 单引号使得 Bash 扩展、变量引用、算术运算和子命令都失效 |
由于反斜杠在单引号里面变成了普通字符,所以如果引号之中,还要使用单引号,不能使用转义,需要是改在双引号之中使用单引号。
1 | $ echo "it's" |
双引号比单引号宽松,虽然双引号里面不会进行文件名扩展,但是一部分特殊字符在双引号里面,仍然具有特殊含义。
三个特殊字符:美元符号($
)、反引号(```)和反斜杠(\
)。这三个字符在双引号之中,依然有特殊含义,会被 Bash 自动扩展。
1 | # 双引号中仍然可以引用变量 |
换行符在双引号之中,会失去特殊含义,Bash 不再将其解释为命令的结束,只是作为普通的换行符。所以可以利用双引号,在命令行输入多行文本。
1 | $ echo "hello |
双引号的另一个常见的使用场合是,文件名包含空格。这时就必须使用双引号(或单引号),将文件名放在里面,否则会被当成两个文件。
1 | $ ls "two words.txt" |
双引号还有一个作用,就是保存原始命令的输出格式。
1 | # 单行输出,`echo`就将所有结果以单行输出,丢弃了所有原始的格式。 |
Here 文档(here document)是一种输入多行字符串的方法,格式如下:
1 | << token |
它的格式分成开始标记(<< token
)和结束标记(token
)。开始标记是 << + Here文档的名称
,名称可以随意取,后面必须是一个换行符
;结束标记是单独一行顶格写的 Here 文档名称
,如果不是顶格,结束标记不起作用。两者之间就是多行字符串的内容。
下面是一个通过 Here 文档输出 HTML 代码的例子。
1 | $ cat << _EOF_ |
Here 文档内部会发生变量替换,同时支持反斜杠转义,但是不支持通配符扩展,双引号和单引号也失去语法作用,变成了普通字符。
1 | $ foo='hello world' |
上面例子中,变量$foo
发生了替换,但是双引号和单引号都原样输出了,表明它们已经失去了引用的功能。
如果不希望发生变量替换,可以把 Here 文档的开始标记放在单引号之中,变量替换就会失效。
1 | $ foo='hello world' |
Here 文档的本质是重定向,它将字符串重定向输出给某个命令,相当于包含了echo
命令。
1 | $ command << token |
所以,Here 字符串只适合那些可以接受标准输入作为参数的命令,对于其他命令无效,比如echo
命令就不能用 Here 文档作为参数。
1 | $ echo << _example_ |
上面例子不会有任何输出,因为 Here 文档对于echo
命令无效。
此外,Here 文档也不能作为变量的值,只能用于命令的参数。
Here 字符串(Here string)是Here 文档的一种变体,使用三个小于号(<<<
)表示。它的作用是将字符串通过标准输入,传递给命令。
1 | <<< string |
有些命令直接接受给定的参数,与通过标准输入接受参数,结果是不一样的。所以才有了这个语法,使得将字符串通过标准输入传递给命令更方便,比如cat
命令只接受标准输入传入的字符串。
1 | $ cat <<< 'hi there' |
上面的第一种语法使用了 Here 字符串,要比第二种语法看上去语义更好,也更简洁。
1 | $ md5sum <<< 'ddd' |
上面例子中,md5sum
命令只能接受标准输入作为参数,不能直接将字符串放在命令后面,会被当作文件名,即md5sum ddd
里面的ddd
会被解释成文件名。这时就可以用 Here 字符串,将字符串传给md5sum
命令。