bash - 为什么 \x0d\x20 删除该行

bash - 为什么 \x0d\x20 删除该行

这是 gedit 编辑器的视图: 在此输入图像描述

以及 vim 编辑器的视图: 在此输入图像描述

然后我尝试 grep 它,如果我使用 Log 而不是 Tog,它会成功 grep,但输出已损坏:

[xiaobai@xiaobai grep]$ grep  Tog test
[xiaobai@xiaobai grep]$ grep  Log test
                               Dtring.valueOf
[xiaobai@xiaobai grep]$ 

然后我查看该文件,它也已损坏:

[xiaobai@xiaobai grep]$ cat test 
                               Dtring.valueOf
[xiaobai@xiaobai grep]$ 

所以我使用十六进制转储:

[xiaobai@xiaobai grep]$ hexdump -C test 
00000000  4c 6f 67 2e 64 28 22 6d  75 73 69 63 22 2c 20 22  |Log.d("music", "|
00000010  4e 41 56 49 47 41 54 4f  52 3a 20 22 20 2b 20 53  |NAVIGATOR: " + S|
00000020  74 72 69 6e 67 2e 76 61  6c 75 65 4f 66 0d 20 20  |tring.valueOf.  |
00000030  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000040  20 20 20 20 20 20 20 20  20 20 20 20 20 44 0d 0a  |             D..|
00000050
[xiaobai@xiaobai grep]$ 

我缩小范围:

[xiaobai@xiaobai grep]$ cat test3
                               D
[xiaobai@xiaobai grep]$ hexdump -C test3
00000000  61 0d 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |a.              |
00000010  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000020  20 44 0d 0a                                       | D..|
00000024
[xiaobai@xiaobai grep]$ echo -e '\x61'
a
[xiaobai@xiaobai grep]$ echo -e '\x61\x0d'
a
[xiaobai@xiaobai grep]$ echo -e '\x61\x0d\x20'

[xiaobai@xiaobai grep]$ echo -e '\x61\x0d\x20\x62'
 b

正如你所看到的,在我附加一个 \x20 字节后,'a' 被删除了。

所以我的问题是,为什么会发生这种情况以及如何在事先不知道某些文件可能包含 \x0d\x20 (例如 grep -r )的情况下摆脱这种情况?

答案1

ASCII 码中的 0 到 31 的字符是控制字符。当发送到终端时,它们用于执行特殊操作。例如,\a(BEL, 0x7) 会敲响终端的铃声。\b(BS, 0x8) 向后移动光标。\n(LF, 0xa) 将光标向下移动一行,\t(TAB 0x9) 将光标移动到下一个表格...

\r(CR, 0xd) 将光标移至第一列。

当您在终端中的 shell 提示符下运行时:

printf 'foo\nbar\n'

printf写入,该设备的 tty 线路规则会将其转换为,这就是为什么您会foo\nbar\n在后的下一行看到。/dev/tty<something>foo\r\nbar\r\nbarfoo

printf 'foo\rbar\n'

将使终端覆盖foobar.

如果您的文件包含控制字符,您可以删除它们,或者如果您想检查它们是否存在,则为它们提供文本表示(例如^MCR 0xd 字符)。\r

不过,您可能不想对 LF 和 TAB 字符执行此操作。所以:

LC_ALL=C tr -d '\0-\10\13-\37\177' < file # to remove them

cat -v < file # to display as ^M

sed -n l < file # to display as \r (also converts TAB to \t)
                # and marks the end of lines with $

请注意,那些sedcat那些也会转换非 ASCII 字符。你可以这样做:

LC_ALL=C sed "$(printf 's/[^\t -\176\200-\377]/^&/g')" < file |
  LC_ALL=C tr '\0-\10\13-\37\177' '@-HK-_?'

仅将 ASCII 控制字符(TAB 和 LF 除外)转换为其^X可视形式(但请注意,并非所有sed实现都支持包含 NUL 字符的输入文件)。

答案2

\x0d\r是将光标带到行首的字符,然后\x20是一个空格,因此它会a用空格覆盖 。如果您使用的是 unix-y 系统,您可能需要考虑\r从输出/文件中删除它,因为如果用于文本输出则不需要它。 “暗示”它\n适用于 *nix,但不适用于 Windows。

相关内容