from:https://zhangge.net/4703.html

昨天,同事告訴我發(fā)現(xiàn)一個詭異的問題,grep無法搜索shell中的變量,著實很驚訝。到他所說的服務(wù)器上試了下,還真是不行!

大概就是這樣一個要求:

①、有個文本為userid.txt,里面每一行一個用戶id,類似如下:

Shell
1
2
3
4
5
0001
0003
0005
0007
0009

②、另外還有一個文本為record.txt,里面是所有用戶的操作記錄,一行一條,并且包含有id,類似如下:

Shell
1
2
3
4
5
6
7
8
9
[12 11 2014 11:03,198 INFO] userId:0001 gilettype:3
[12 11 2014 12:12,198 INFO] userId:0002 gilettype:3
[12 11 2014 13:02,198 INFO] userId:0003 gilettype:1
[12 11 2014 14:33,198 INFO] userId:0001 gilettype:3
[12 11 2014 15:13,198 INFO] userId:0002 gilettype:2
[12 11 2014 16:43,198 INFO] userId:0003 gilettype:1
[12 11 2014 17:32,198 INFO] userId:0001 gilettype:3
[12 11 2014 18:16,198 INFO] userId:0002 gilettype:1
[12 11 2014 19:25,198 INFO] userId:0003 gilettype:2

③、現(xiàn)在他要求循環(huán)取出userid.txt中每一行ID值,然后去record.txt去查找并保存結(jié)果。

實現(xiàn)這個需求原本很簡單,根本難不倒他,只要使用while read + grep 就能搞定。可問題是明明record.txt里面包含這些id,卻無法輸出結(jié)果??

我順便寫了一個測試腳本測試了下:

Shell
1
2
3
4
5
6
#!/bin/bash
while read userId;
do
        echo $userId
        grep $userId record.txt
done <userid.txt

發(fā)現(xiàn)腳本可以打印echo $userId,卻無法grep到??而實際上record.txt里面是有這個id的!還真詭異!

先百度搜索了一下【grep 無法搜索變量】,還真有不少類似問題,比如:http://bbs.chinaunix.net/thread-123113-1-1.html

根據(jù)經(jīng)驗,對于這種詭異的問題,我首先會想到是不是系統(tǒng)有問題,要是系統(tǒng)有問題你怎么折騰都是錯!

于是把他的文件拷貝到其他服務(wù)器,發(fā)現(xiàn)居然可以了!!!難道真是系統(tǒng)問題么?

第一臺是SUSE Linux,第二臺是Centos,難道和系統(tǒng)發(fā)行版有關(guān)系?

后來,同事在第二臺服務(wù)器上完成了他的項目。但這個問題卻一直留在我的腦子里,揮之不去。


 

今天,我決定再次研究下這個問題,看看是不是有其他原因。我先在那臺SUSE Linux上,手工編寫所需文件:

[root@localhost ~]# vim 1.txt

Shell
1
2
3
1111
3333
5555

[root@localhost ~]# vim 2.txt

Shell
1
2
3
4
5
6
1111
2222
3333
4444
5555
6666

[root@localhost ~]# vim test.sh

Shell
1
2
3
4
5
#!/bin/bash
cat 1.txt|while read userId;
do
        grep $userId 2.txt
done

結(jié)果,發(fā)現(xiàn)居然可以輸出結(jié)果!證明這系統(tǒng)沒有問題啊!于是再一次測試了一下昨天的腳本,發(fā)現(xiàn)還是無法輸出。

于是使用 -x 參數(shù) 調(diào)試一下腳本:

先修改腳本代碼:

Shell
1
2
3
4
5
6
#!/bin/bash
cat userid.txt|while read userId;
do
        grep $userId record.txt
        sleep 3
done

然后,帶 -x 參數(shù)執(zhí)行:

Shell
1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]#  sh -x test
+ cat userid.txt
+ read userId
+ grep $'0001\r' record.txt
+ sleep 3
+ read userId
+ grep $'0003\r' record.txt
+ sleep 3
+ read userId
+ grep $'0005\r' record.txt
+ sleep 3

難怪找不到,grep的變量已經(jīng)變了!0001變成了 $'0001\r' !

看到\r,立馬想到是文本中的換行符,可為毛會輸出換行符呢?想到博客以前寫的《Linux終端:用cat命令查看不可見字符》,繼續(xù)改了一下代碼:

Shell
1
2
3
4
5
6
#!/bin/bash
cat -A userid.txt|while read userId;
do
        grep $userId record.txt
        sleep 3
done

執(zhí)行后恍然大悟:

Shell
1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]#  sh -x test
+ cat -A userid.txt
+ read userId
+ grep '0001^M$' record.txt
+ sleep 3
+ read userId
+ grep '0003^M$' record.txt
+ sleep 3
+ read userId
+ grep '0005^M$' record.txt
+ sleep 3

原來是dos下的文本格式,問了下同事,他還真是從Windows下導(dǎo)過來的! — —||

也就是說,userid.txt這個文本的換行符是Windows格式,在Linux下讀取會帶有^M。

所以解決上述問題,就很明了了,要么轉(zhuǎn)換userid.txt的換行格式,要不就修改代碼,去掉多余的字符!

試了下轉(zhuǎn)換格式,發(fā)現(xiàn)居然轉(zhuǎn)換不成功,可能是我沒找對方法,暫時先不折騰了!

直接如下修改代碼,就搞定了:

Shell
1
2
3
4
5
6
7
#!/bin/bash
cat -A userid.txt|while read userId;
do
        #利用cut命令取出 ^ 之前的數(shù)字部分:
        id=`echo $userId | cut -d"^" -f1`
        grep $id record.txt
done

好了,搞了半天原來是dosunix的換行符問題!o(︶︿︶)o 唉!還是經(jīng)驗不足啊!

網(wǎng)上那些問grep無法搜索變量的朋友,趕緊看看是不是文本格式造成的!現(xiàn)在,讓我很納悶的是,為毛在另一臺centos系統(tǒng)可以直接grep??為什么在SUSE系統(tǒng)就不行?

如果和發(fā)行版沒關(guān)系的話,那造成2個不同結(jié)果的原因就只有一個:在我用sz+rz命令將所有文本傳送到centos的過程中,文件很可能被自動轉(zhuǎn)格式了!好吧,具體就不深究了,有興趣的可以試試看。