首页 > 解决方案 > 为什么在查看某些文件时,终端输出中会出现“^M”?

问题描述

我正在尝试使用 curl 将文件发送到端点并将文件保存到机器上。

从 Linux 发送 curl 并将其保存在机器上效果很好,但是从 Windows 执行相同的 curl^M会在行的每一端添加字符。

我在保存文件之前正在打印文件,但看不到^M. 只有在保存后查看远程机器上的文件才会显示^M

一个简单的字符串替换似乎不起作用。

为什么^M被添加?我怎样才能防止这种情况?

标签: linuxterminalasciicontrol-characters

解决方案


快速回答:那是回车。它们是 Windows 如何编码文本文件的无害但轻微刺激性的工件。您可以使用dos2unix. 您可以将大多数文本编辑器配置为使用“Unix 行尾”或“LF 行尾”,以防止它们出现在您将来从 Windows PC 创建的新文件中。


长答案(带有一些历史琐事):

在纯文本文件中,当您创建新行(通过按 Enter/Return)时,文件中会嵌入“换行符”。在 Unix/Linux 上,这是一个单一的字符,'\n',即“换行符”。在 Windows 上,这是两个连续的字符,'\r\n',即“回车”,后跟“换行”。

当物理电传终端(其行为很像打字机)仍在使用时,“换行”字符的意思是“将纸张向上移动到下一行”,而“回车”字符的意思是“将托架一直滑过打字头在最左边”。从一开始,几乎所有的电传终端都支持隐式回车;即,触发换行将自动触发回车。致力于后来演变成 Windows 的开发人员决定最好包含显式回车,以防万一(出于某种原因)电传打字机不隐式执行回车。另一方面,Unix 开发人员选择使用隐式回车的假设。

回车和换行是ASCII 控制字符,这意味着它们没有作为独立可打印字符的可见表示,而是影响输出光标本身(在这种情况下,输出光标的位置)。

您看到的“^M”是回车符的替代表示,由不完全“烹饪”其输出的程序使用(即,不应用某些 ASCII 控制字符的效果)。(其他控制字符有其他以“^”开头的表示,并且“^”字符也用于表示某些Unix程序中的“ctrl”键盘键nano。)

您可以使用dos2unix将行尾从 Windows 样式转换为 Unix 样式。

$ curl https://example.com/file_with_crlf.txt | dos2unix > file.txt

在某些发行版中,默认情况下包含此工具,在其他发行版中,它可以通过包管理器安装(例如,在 Ubuntu 上sudo apt install dos2unix)。也存在一个包 ,unix2dos用于逆。

大多数用于编码的“智能”文本编辑器(Sublime、Atom、VS Code、Notepad++ 等)都可以愉快地使用 Windows 风格或 Unix 风格的行尾进行读写(这可能需要更改一些配置选项)。通常,通过扫描文件的内容来自动检测行尾,并且通常使用操作系统的本机行尾创建新文件(默认情况下)。甚至新版本的记事本也支持 Unix 风格的行尾。另一方面,一些 Unix 工具在出现 Windows 风格的换行符时会产生奇怪的结果。如果您的代码库将被 Unix 和 Windows 操作系统上的人们使用,那么最好的办法是在任何地方使用 Unix 风格的行尾。

Windows 上的 Git 也有一个可选模式,它用 Windows 样式的换行符签出所有文件,但用 Unix 样式的换行符将它们重新签入。


旁注(有趣,但与您的问题没有直接关系):

回车实际上所做的(在现代虚拟终端上,无论是 Windows 还是 Unix)是将输出光标移动到行首。如果您使用不带换行符的回车,您可以“覆盖”已经打印的字符串的一部分。

$ printf "dogdog" ; printf "\rcat\n"
catdog

一些 Unix 程序使用它来异步更新最后一行输出的一部分,以实现诸如实时更新进度指示器之类的东西。例如,curl如果文件内容通过管道传输到其他地方,它会在标准输出上显示下载进度。

另外:如果你有一个工具可以尽可能地解释 Windows 风格的行尾,并且你给它一个带有 Unix 风格的行尾的字符串,比如“hello\nworld”,你会得到这样的输出:

hello
     world

幸运的是,这样的实现非常少见,一般来说,绝大多数 Windows 工具都可以毫无问题地渲染 Unix 风格的行尾与 Windows 风格的行尾相同。


推荐阅读