![在 Linux shell 中,为什么反斜杠换行符不会引入空格?](https://linux22.com/image/1418820/%E5%9C%A8%20Linux%20shell%20%E4%B8%AD%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E5%8F%8D%E6%96%9C%E6%9D%A0%E6%8D%A2%E8%A1%8C%E7%AC%A6%E4%B8%8D%E4%BC%9A%E5%BC%95%E5%85%A5%E7%A9%BA%E6%A0%BC%EF%BC%9F.png)
在使用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 termios
、man tty_ioctl
.man console_ioctl
等下。