在 Linux shell 中,为什么反斜杠换行符不会引入空格?

在 Linux shell 中,为什么反斜杠换行符不会引入空格?

在使用Linux shell时,我遇到以下情况:

$ A=B\
> C
$ echo $A
BC

在我看来,当换行符遇到转义符时,它不能是 CR 字符,但它仍然是换行符。 应该echo $A被解释为echo B newline C,而换行符应该是 的 IFS echo。因此输出应该是B C而不是BC

为什么我会得到这样的输出?

答案1

引述man bash,部分引用

未加引号的反斜杠 ( \) 是转义字符。它保留其后下一个字符的字面值,但 除外<newline>。如果\<newline>出现一对,并且反斜杠本身未加引号,则\<newline>被视为行延续(即,它会从输入流中删除并被有效忽略)。

这使您可以将脚本中非常长的命令/命令序列(管道和转换输出等)分成多行以便于阅读。


为了让它按照您的期望处理换行符,只需将值(以及之后对变量的任何使用)括在引号中。

$ A="B
> C"
$ echo "$A"
B
C

摘自同一节:

将字符括在单引号中会保留引号内每个字符的文字值。...

将字符括在双引号中会保留引号内所有字符的文字值,但 $、`、\和启用历史扩展时的 ! 除外。字符 $ 和 ` 在双引号内保留其特殊含义。反斜杠仅在后跟以下字符之一时才保留其特殊含义:$、`、"、\或 。

答案2

将“为什么”回答为“为什么这有用”:

反斜杠换行符用于行延续分割过长的行:

在 shell 脚本中,行尾的反斜杠使 shell 在执行脚本时忽略换行符。这通常用于将脚本文件中的长行拆分为多个文本行,shell 会将这些文本行作为单个脚本行处理。

例如,命令

git log --tags --branches HEAD FETCH_HEAD ORIG_HEAD --graph --decorate --pretty=oneline --simplify-by-decoration

可以写成

git log --tags --branches HEAD FETCH_HEAD ORIG_HEAD \
    --graph --decorate --pretty=oneline --simplify-by-decoration

答案3

警告:仅当反斜杠是行中的最后一个字符时,它才会续行。

这有点离题了;我在这里把它作为一个容易被忽视的要点。如果你不小心在 shell 脚本中以\(反斜杠后跟空格或制表符) 而不是结尾,\你可能会发现你的脚本停止运行或以其他方式表现异常,即使反斜杠似乎最后一个字符。

如果你正在使用使用命令很容易发现这个问题:set list,该命令会在每一行末尾放置一个$,让您可以发现尾随空格或制表符。 :set nolist关闭 vi 的这个功能。

答案4

A=B\
C

表示“A 等于字符串 B,后面跟着一个我忽略的换行符,后面跟着一个 C”

就 shell 而言,您输入的内容中没有 CR。Linux/Unix 行尾是换行符 (LF),而不是 CR。CR 是作为终端处理的一部分发出的。大多数终端需要换行符来删除一行,需要回车符来将光标送回左侧。当向终端发送换行符时,内核会插入 CR,当终端需要它时 - 换句话说,它对 shell 不可见。请注意,例如,可视化编辑器可能会分开使用 CR 和 LF - 到下一个要重写的屏幕的最少字符可能涉及 LF(直接向下移动页面而不更改列)。

稍微令人困惑的是,键盘也有输入转换。 Enter 键通常发送回车符 (Control-M)。但要识别已输入的命令,shell 需要看到行尾。stty因此,一个附加参数向内核终端处理描述了输入的 CR 应转换为行尾。因此,shell仍然没有看到 CR。

最终结果是终端发送:

A=B\<CR>C<CR>

shell 接收:

A=B\<LF>C<LF>

shell 将其解析为“哦,反斜杠换行符 - 我只是忽略它”并最终得到:

A=BC<LF>

在输出时,内核将命令输入期间发送到终端的序列修改为:

A=B\<CR><LF>C<CR><LF>

终端处理的内核处理由 shell 命令管理stty,并且根据实现(Linux、Mac OS X、*BSD),底层细节应该在man termiosman tty_ioctl.man console_ioctl等下。

相关内容