特别是我正在尝试将所有
\r\n
转变为\r\r\n
。这是因为 iCloud 的 IMAP 服务器发送 \r\r\n
破坏了协议和所有敏感性(我唯一的工作理论是他们这样做了,所以他们只能在几年前发布的版本中使用自己的 IMAP 客户端),并且我需要编写单元测试模拟这个。
要使其在标准 Unix 工具中工作非常棘手,因为它们处理行结尾的方式。
sed 's/\r\n/\r\r\n/g'
- 不,什么也没做
sed 's/\r/\r\r/g'
- 也什么也不做
tr
在处理字符串方面没有多大用处;它仅对单个字符进行操作,并且似乎保留了字符数。
我实际上不确定如何使用 Unix 工具来做这么低级的事情。 最坏的情况下,我可以用几行 C 语言来完成此操作,但我想学习如何更标准地执行此操作。
根据 Jim 的回答中的讨论,Mac OS X (BSD) 上的 sed 版本似乎与 Linux 的行为不同。 理想情况下,我需要一个 Mac 解决方案,尽管我或多或少可以在另一台机器上完成此任务。
如果您使用
bash
作为 shell,则可以使用其 ANSI C 引用 功能来强制 Mac OS X sed
根据您的需要工作。
sed -e $'s/$/\r\r/'
$'...'
是一个 ANSI C 带引号的字符串。 其中大部分(仅)字符没有改变;两个 \r
序列被字符串中的回车符替换。
例如:
$ sed -e $'s/$/\r\r/' genouterr.sh | odx
0x0000: 23 21 2F 62 69 6E 2F 62 61 73 68 0D 0D 0A 66 6F #!/bin/bash...fo
0x0010: 72 20 69 20 69 6E 20 7B 30 31 2E 2E 35 30 7D 0D r i in {01..50}.
0x0020: 0D 0A 64 6F 0D 0D 0A 20 20 65 63 68 6F 20 22 73 ..do... echo "s
0x0030: 74 64 6F 75 74 20 24 69 22 0D 0D 0A 20 20 65 63 tdout $i"... ec
0x0040: 68 6F 20 22 73 74 64 65 72 72 20 24 69 22 20 3E ho "stderr $i" >
0x0050: 26 32 0D 0D 0A 64 6F 6E 65 0D 0D 0A &2...done...
0x005C:
$
十六进制转储(
odx
是一个自制程序,但我喜欢它的格式)显示每个换行符(0A)之前有两个\r
(0D)字节,这在原始文件中是不存在的。 显然,十六进制转储程序的选择不会影响 sed
命令和 ANSI C 引用机制的有效性。
如果您需要将 CRLF 更改为 CRCRLF,那么您可以使用:
sed -e $'s/\r$/\r\r/'
如果您想删除回车符,但仅在行尾删除,那么您可以使用:
sed -e $'s/\r\r*$//'
(
tr
可用于删除所有回车符,但不仅限于换行符之前的回车符。)
您可以使用行尾锚字符“$”来完成您想要的操作:
% od -c foo
0000000 l i n e 1 \r \n l i n e 2 \r \n l i
0000020 n e 3 \r \n
0000025
% sed 's/\r$/\r\r/g' < foo > bar
% od -c bar
0000000 l i n e 1 \r \r \n l i n e 2 \r \r \n
0000020 l i n e 3 \r \r \n
0000030
上面的代码适用于 GNU sed,但不适用于 BSD sed(它不处理 正如人们在替换字符串中所期望的那样)。 在 Mac 或其他 BSD 风格的 sed 变体上,您应该能够完成 通过指定反斜杠转义的literal(空格)ASCII 返回来进行所需的替换 性格。
请参阅此问题了解更多详细信息。
在 OSX 上执行此操作的一种方法是使用 awk:
awk '/\r$/ {printf "%s\r\n", $0}' file
如果您只想要
sed 那么这应该适用于 OSX:
sed -i.bak "s/"$'\r'"$/&&/" file