Bash

bash - 為什麼 x0dx20 刪除該行

  • May 8, 2015

這是來自 gedit 編輯器的視圖: 在此處輸入圖像描述

以及來自 vim 編輯器的視圖: 在此處輸入圖像描述

然後我嘗試 grep 它,如果我輸入 Log 而不是 Tog,它會成功 grep,但輸出已損壞:

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

然後我 cat 文件,它也已損壞:

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

所以我使用 hexdump:

[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,我如何才能擺脫這種情況?

ASCII 中程式碼 0 到 31 的字元是控製字元。當發送到終端時,它們習慣於做特殊的事情。例如,\a(BEL, 0x7) 敲響終端的鈴聲。\b(BS, 0x8) 向後移動游標。\n(LF, 0xa) 將游標向下移動一行,\t(TAB 0x9) 將游標移動到下一個列表…

\r(CR, 0xd) 將游標移動到第一列。

當您在終端的 shell 提示符下執行時:

printf 'foo\nbar\n'

printf寫入foo\nbar\n/dev/tty<something>,該設備的 tty 線路規程將其轉換為foo\r\nbar\r\n,這就是為什麼您bar在之後的下一行看到的原因foo

printf 'foo\rbar\n'

會讓終端foo覆蓋bar.

如果您的文件包含控製字元,您可以刪除它們,或者如果您想檢查它們的存在,則可以給它們一個文本表示(例如^M,或者對於 CR 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 字元的輸入文件)。

引用自:https://unix.stackexchange.com/questions/202198