|
對于不識別CRLF格式文本文件的grep命令(比如Linux和Cygwin下面的grep)來說,回車符(carriage return)\r 并不是有特殊含義的字符,而是普通字符,所以如果要匹配回車符,只需要找到一個(gè)能夠輸入回車符這個(gè)字符的方式即可,而bash 的$'\r' 就能滿足要求。下面舉例說明。
CVS 在windows的CVS目錄下Tag文件是是DOS格式文件文件,把這個(gè)文件拷貝到Linux,查看內(nèi)容如下:
]# cat Tag
Trelease
]# cat Tag | od -c
0000000 T r e l e a s e \r \n
0000012
現(xiàn)在要匹配行尾的e ,為了對比,我們還建立一個(gè)Tag文件的副本TagUnix,使用dos2unix 命令將它轉(zhuǎn)成Unix風(fēng)格的文本文件,如下所示:
]# cat TagUnix | od -c
0000000 T r e l e a s e \n
0000011
使用e$ 作為模式,結(jié)果如下
]# grep e$ Tag
]# grep e$ TagUnix
Trelease
這是說明因?yàn)門ag的行尾并不是e ,而是e\r 。那么使用e$'\r'$ 作為模式如何?結(jié)果如下:
]# grep e$'\r'$ Tag
]#
得到一個(gè)空行輸出。這是為什么?這說明,實(shí)際上有一行匹配,但是由于這一行的內(nèi)容包含\r,而它對于終端是有特殊含義的,所以終端就在輸出\r的時(shí)候,將光標(biāo)回到行首,于是乎之前輸出的內(nèi)容就看不到,就只能看到一個(gè)空行(這似乎說明,Linux下面兼容CRLF格式的不是終端,而是輸出文本文件的命令如more, cat等等)。 關(guān)于輸出的差別,補(bǔ)充一個(gè)例子(在centos是如此,在cygwin下面也是如此):
]# grep '3306' my.ini | od -c
0000000 p o r t = 3 3 0 6 \r \n p o r t =
0000020 3 3 0 6 \r \n
0000026
]# grep '3306'$'\r''$' my.ini | od -c
0000000 p o r t = 3 3 0 6 \r \n p o r t =
0000020 3 3 0 6 \r \n
0000026
]# grep '3306' my.ini
port=3306
port=3306
]# grep '3306'$'\r''$' my.ini
]#
其中my.ini是windows下mysql數(shù)據(jù)庫的配置文件,是以CRLF結(jié)尾的。上面的例子中,輸出結(jié)果通過od命令查看是一樣的,但是顯示到終端后,顯示效果不一樣。這種情況一時(shí)讓我有點(diǎn)糊涂,我只能猜測如下:當(dāng)EOF是CRLF的時(shí)候,grep命令實(shí)際上是能夠識別出來的,如果是正常字符串那么只有除CRLF的部分參與匹配,得到匹配行的內(nèi)容是3306,然后輸出這行內(nèi)容的時(shí)候,再輸出一個(gè)EOF,即CRLF(假設(shè)終端處理一起的CRLF時(shí),實(shí)際上只輸出一個(gè)換行)。當(dāng)匹配模式中包含\r的時(shí)候,grep將這個(gè)文件識別為EOF是LF,那么得到匹配內(nèi)容3306$'\r'這這一行,輸出這行內(nèi)容(此時(shí)這行內(nèi)容包含CR,而CR單獨(dú)出現(xiàn),沒有與后面的LF連在一起,終端解釋為回車),然后再輸出一個(gè)EOF,即LF。從最終輸出內(nèi)容的十六進(jìn)制來看,兩者一樣,但是對于終端顯示,兩者行為不同。
解決顯式效果的辦法也簡單,重定向到文件,再輸出來,或者直接重定向到more、cat等命令(是上面重定向到文件的一種特殊情況),或者通過tr命令刪除\r,都可以。如下所示:
]# grep e$'\r'$ Tag | more
Trelease
]# grep e$'\r'$ Tag | cat
Trelease
]# grep e$'\r'$ Tag | tr -d '\r'
Trelease
|