引号和转义

Bash 只有一种数据类型,就是字符串。不管用户输入什么数据,Bash 都视为字符串。因此,字符串相关的引号和转义,对 Bash 来说就非常重要。

转义

某些字符在 Bash 里面有特殊含义(比如$&*)。

$ echo $date

$

上面例子中,输出$date不会有任何结果,因为$是一个特殊字符。

如果想要原样输出这些特殊字符,就必须在它们前面加上反斜杠,使其变成普通字符。这就叫做“转义”(escape)。

$ echo \$date
$date

上面命令中,只有在特殊字符$前面加反斜杠,才能原样输出。

反斜杠本身也是特殊字符,如果想要原样输出反斜杠,就需要对它自身转义,连续使用两个反斜线(\\)。

$ echo \\
\

上面例子输出了反斜杠本身。

反斜杠除了用于转义,还可以表示一些不可打印的字符。

  • \a:响铃
  • \b:退格
  • \n:换行
  • \r:回车
  • \t:制表符

如果想要在命令行使用这些不可打印的字符,可以把它们放在引号里面,然后使用echo命令的-e参数。

$ echo a\tb
atb $ echo -e "a\tb"
a b

上面例子中,命令行直接输出不可打印字符\t,Bash 不能正确解释。必须把它们放在引号之中,然后使用echo命令的-e参数。

换行符是一个特殊字符,表示命令的结束,Bash 收到这个字符以后,就会对输入的命令进行解释执行。换行符前面加上反斜杠转义,就使得换行符变成一个普通字符,Bash 会将其当作空格处理,从而可以将一行命令写成多行。

$ mv \
/path/to/foo \
/path/to/bar # 等同于
$ mv /path/to/foo /path/to/bar

上面例子中,如果一条命令过长,就可以在行尾使用反斜杠,将其改写成多行。这是常见的多行命令的写法。

单引号

Bash 允许字符串放在单引号或双引号之中,加以引用。

单引号用于保留字符的字面含义,各种特殊字符在单引号里面,都会变为普通字符,比如星号(*)、美元符号($)、反斜杠(\)等。

$ echo '*'
* $ echo '$USER'
$USER $ echo '$((2+2))'
$((2+2)) $ echo '$(echo foo)'
$(echo foo)

上面命令中,单引号使得 Bash 扩展、变量引用、算术运算和子命令,都失效了。如果不使用单引号,它们都会被 Bash 自动扩展。

由于反斜杠在单引号里面变成了普通字符,所以如果单引号之中,还要使用单引号,不能使用转义,需要在外层的单引号前面加上一个美元符号($),然后再对里层的单引号转义。

# 不正确
$ echo it's # 不正确
$ echo 'it\'s' # 正确
$ echo $'it\'s'

不过,更合理的方法是改在双引号之中使用单引号。

$ echo "it's"
it's

双引号

双引号比单引号宽松,大部分特殊字符在双引号里面,都会失去特殊含义,变成普通字符。

$ echo "*"
*

上面例子中,通配符*是一个特殊字符,放在双引号之中,就变成了普通字符,会原样输出。这一点需要特别留意,这意味着,双引号里面不会进行文件名扩展。

但是,三个特殊字符除外:美元符号($)、反引号(`)和反斜杠(\)。这三个字符在双引号之中,依然有特殊含义,会被 Bash 自动扩展。

$ echo "$SHELL"
/bin/bash $ echo "`date`"
Mon Jan 27 13:33:18 CST 2020

上面例子中,美元符号($)和反引号(`)在双引号中,都保持特殊含义。美元符号用来引用变量,反引号则是执行子命令。

$ echo "I'd say: \"hello!\""
I'd say: "hello!" $ echo "\\"
\

上面例子中,反斜杠在双引号之中保持特殊含义,用来转义。所以,可以使用反斜杠,在双引号之中插入双引号,或者插入反斜杠本身。

换行符在双引号之中,会失去特殊含义,Bash 不再将其解释为命令的结束,只是作为普通的换行符。所以可以利用双引号,在命令行输入多行文本。

$ echo "hello
world"
hello
world

上面命令中,Bash 正常情况下会将换行符解释为命令结束,但是换行符在双引号之中就失去了这种特殊作用,只用来换行,所以可以输入多行。echo命令会将换行符原样输出,显示的时候正常解释为换行。

双引号的另一个常见的使用场合是,文件名包含空格。这时就必须使用双引号,将文件名放在里面。

$ ls "two words.txt"

上面命令中,two words.txt是一个包含空格的文件名,否则就会被 Bash 当作两个文件。

双引号会原样保存多余的空格。

$ echo "this is a     test"
this is a test

双引号还有一个作用,就是保存原始命令的输出格式。

# 单行输出
$ echo $(cal)
一月 2020 日 一 二 三 四 五 六 1 2 3 ... 31 # 原始格式输出
$ echo "$(cal)"
一月 2020
日 一 二 三 四 五 六
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

上面例子中,如果$(cal)不放在双引号之中,echo就会将所有结果以单行输出,丢弃了所有原始的格式。

Here 文档

Here 文档(here document)是一种输入多行字符串的方法,格式如下。

<< token
text
token

它的格式分成开始标记(<< token)和结束标记(token)。开始标记是两个小于号 + Here 文档的名称,名称可以随意取,后面必须是一个换行符;结束标记是单独一行顶格写的 Here 文档名称,如果不是顶格,结束标记不起作用。两者之间就是多行字符串的内容。

下面是一个通过 Here 文档输出 HTML 代码的例子。

$ cat << _EOF_
<html>
<head>
<title>
The title of your page
</title>
</head> <body>
Your page content goes here.
</body>
</html>
_EOF_

Here 文档内部会发生变量替换,同时支持反斜杠转义,但是不支持通配符扩展,双引号和单引号也失去语法作用,变成了普通字符。

$ foo='hello world'
$ cat << _example_
$foo
"$foo"
'$foo'
_example_ hello world
"hello world"
'hello world'

上面例子中,变量$foo发生了替换,但是双引号和单引号都原样输出了,表明它们已经失去了引用的功能。

如果不希望发生变量替换,可以把 Here 文档的开始标记放在单引号之中。

$ foo='hello world'
$ cat << '_example_'
$foo
"$foo"
'$foo'
_example_ $foo
"$foo"
'$foo'

上面例子中,Here 文档的开始标记(_example_)放在单引号之中,导致变量替换失效了。

Here 文档的本质是重定向,它将字符串重定向输出给某个命令,相当于包含了echo命令。

$ command << token
string
token # 等同于 $ echo string | command

上面代码中,Here 文档相当于echo命令的重定向。

所以,Here 字符串只适合那些可以接受标准输入作为参数的命令,对于其他命令无效,比如echo命令就不能用 Here 文档作为参数。

$ echo << _example_
hello
_example_

上面例子不会有任何输出,因为 Here 文档对于echo命令无效。

此外,Here 文档也不能作为变量的值,只能用于命令的参数。

Here 字符串

Here 文档还有一个变体,叫做 Here 字符串(Here string),使用三个小于号(<<<)表示。

<<< string

它的作用是将字符串通过标准输入,传递给命令。

有些命令直接接受给定的参数,与通过标准输入接受参数,结果是不一样的。所以才有了这个语法,使得将字符串通过标准输入传递给命令更方便,比如cat命令只接受标准输入传入的字符串。

$ cat <<< 'hi there'
# 等同于
$ echo 'hi there' | cat

上面的第一种语法使用了 Here 字符串,要比第二种语法看上去语义更好,也更简洁。

$ md5sum <<< 'ddd'
# 等同于
$ echo 'ddd' | md5sum

上面例子中,md5sum命令只能接受标准输入作为参数,不能直接将字符串放在命令后面,会被当作文件名,即md5sum ddd里面的ddd会被解释成文件名。这时就可以用 Here 字符串,将字符串传给md5sum命令。

shell中的引号和转义的更多相关文章

  1. Linux Shell中有三种引号的用法

    Linux Shell中有三种引号,分别为双引号(" ").单引号(' ')以及反引号(` `). 其中双引号对字符串中出现的$.''.`和\进行替换:单引号不进行替换,将字符串中 ...

  2. Shell中反引号和$()的区别

    Shell中可以用来实现变量代换的命令有两种,一种是由反引号括起来的一条命令另一种是由$()括起来一条命令,shell先执行这条命令,然后见输出结果立刻代换到当前命令行中. 例如定义一个变量存放dat ...

  3. Shell中反引号(`)与$()用法的区别

    今天有人提问: echo `echo \\\\\\\w` echo $(echo \\\\\\\w) 为什么输出的不一样? 这就引申出了另一个问题:反引号与$()有没有区别? 这是一个非常有意思的问题 ...

  4. shell中的引号

    单引号: 所见即所得 原封不动输出 双引号: 与单引号类似 特殊符号进行解析 ( $ $() `` ! ) 无引号: 与双引号类似 支持通配符( {} * ) 反引号: 优先执行 优先执行里面的命令, ...

  5. Shell中三种引号的用法及区别

    Linux Shell中有三种引号,分别为双引号(" ").单引号(' ')以及反引号(` `). 其中双引号对字符串中出现的$.''.`和\进行替换:单引号不进行替换,将字符串中 ...

  6. 【转】shell的反引号、单引号、双引号的作用

    Linux Shell中有三种引号,分别为双引号(" ").单引号(' ')以及反引号(` `). 其中双引号对字符串中出现的$.''.`和\进行替换:单引号不进行替换,将字符串中 ...

  7. shell中的双引号,单引号,反引号

    在shell中引号分为三种:单引号,双引号和反引号. 单引号 ‘ 由单引号括起来的字符都作为普通字符出现.特殊字符用单引号括起来以后,也会失去原有意义,而只作为普通字符解释.单引号用于保持引号内所有字 ...

  8. shell中引号的作用(转)

    引号的作用 1 双引号(“”) 1)使用””可引用除字符$(美元符号).`(反引号).\(反斜线)外的任意字符或字符串.双引号不会阻止shell对这三个字符做特殊处理(标示变量名.命令替换.反斜线转义 ...

  9. Linux中的元字符和转义符 单引号 硬引号 双引号 软引号

    Linux中的元字符和转义符  单引号  硬引号  双引号  软引号 Linux就这个范儿 Linux就这个范儿 P182单引号:硬引号,所有元字符特殊意义都会关掉双引号:软引号,只允许出现特定元字符 ...

随机推荐

  1. 1_JVM与Java体系结构

    目录 JVM与Java体系结构 前言 架构师每天都在思考什么? 为什么要学习JVM Java vs C++ 推荐书籍 Java生态圈 字节码 多语言混合编程 Java发展的重大事件 虚拟机与Java虚 ...

  2. (数据科学学习手札111)geopandas 0.9.0重要新特性一览

    本文示例文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在几天前,geopandas释放了其最新正式版 ...

  3. AmazonS3 使用AWS SDK for Java实现跨源资源共享 (CORS)

    CORS 配置 创建 CORS 配置并对存储桶设置该配置 通过添加规则来检索并修改配置 向存储桶添加修改过的配置 删除配置 import com.amazonaws.AmazonServiceExce ...

  4. 欢迎参加3月活动:AWS 在线研讨会与阿里云 RISC-V 应用创新大赛

    3月份我们在帮合作云厂商 Amazon Web Services(AWS) 与阿里云推广2个活动,欢迎感兴趣的园友参加. 活动一:亚马逊云科技在线研讨会:借助 DGL 实现实时欺诈检测 博客园专属报名 ...

  5. Fishing Master HDU - 6709

    题目链接:https://vjudge.net/problem/HDU-6709 题意:给出n条鱼的抓捕时间k和煮鱼时间a[i],你要在最短时间把所有鱼都煮了.(注意你只有一口锅) 思路:首先我们必须 ...

  6. 轻松理解 Java 静态代理/动态代理

    目录 什么是代理模式 定义 代理模式的主要角色 优点 缺点 静态代理 动态代理 JDK原生动态代理 例子 分析 小结 CGLIB动态代理 例子 分析 final类型 其他方案 尾声 理解Java动态代 ...

  7. 快速了解 JavaScript ES2019 的五个新增特性

    ES2019 规范是对 JavaScript 的一个较小的补充,但它仍然带来了一些有用的功能.本文将向你展示五个 ES2019 新增的特性,这些特性或许可以让你的编程轻松一点.这些特性包括 trimS ...

  8. 【Java】7.0 进制转换

    [二进制转十进制] public static void main(String args[]) { Scanner sc = new Scanner(System.in); System.out.p ...

  9. OO_Unit3_Summary

    JML这一单元是真的有含金量,很有难度.而且这难点和前两单元完全不同,前两单元是容易架构混乱导致细节出问题,JML单元是读不懂JML规格的话架构都构不出来,以及即使能够读懂JML规格了,让自己写规格的 ...

  10. 基于gitlab的项目管理流程

    框架 背景 个人是不太愿意使用用户体验差的软件来做项目管理,行业内,要找到这么一款软件,又要符合自己的需求,着实不容易.要免费,易用性要好,要安全,要有数据统计.而程序员的世界,SVN 之后,可能没有 ...