1. 程式人生 > >grep無法查詢shell傳過來的變數?先注意一下文字格式吧!

grep無法查詢shell傳過來的變數?先注意一下文字格式吧!

昨天,同事告訴我發現一個詭異的問題,grep 無法搜尋 shell 中的變數,著實很驚訝。到他所說的伺服器上試了下,還真是不行!

大概就是這樣一個要求:

①、有個文字為 userid.txt,裡面每一行一個使用者 id,類似如下:

Shell
12345 00010003000500070009

②、另外還有一個文字為 record.txt,裡面是所有使用者的操作記錄,一行一條,並且包含有 id,類似如下:

Shell
123456789 [1211201411:03,198INFO]userId:0001gilettype:3[1211201412:12,198INFO]userId:0002gilettype:3[1211201413:02,198INFO]userId:0003gilettype:1[1211201414:33,198INFO]userId:0001gilettype:3[1211201415:13,198INFO]userId:0002gilettype:2[1211201416:43,198INFO]userId:0003gilettype:1[12
11201417:32,198INFO]userId:0001gilettype:3[1211201418:16,198INFO]userId:0002gilettype:1[1211201419:25,198INFO]userId:0003gilettype:2

③、現在他要求迴圈取出 userid.txt 中每一行 ID 值,然後去 record.txt 去查詢並儲存結果。

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

我順便寫了一個測試指令碼測試了下:

Shell
123456 #!/bin/bashwhilereaduserId;doecho$userIdgrep$userIdrecord.txtdone<userid.txt

發現指令碼可以列印 echo $userId,卻無法 grep 到??而實際上 record.txt 裡面是有這個 id 的!還真詭異!

根據經驗,對於這種詭異的問題,我首先會想到是不是系統有問題,要是系統有問題你怎麼折騰都是錯!

於是把他的檔案拷貝到其他伺服器,發現居然可以了!!!難道真是系統問題麼?

第一臺是 SUSE Linux,第二臺是 Centos,難道和系統發行版有關係?

後來,同事在第二臺伺服器上完成了他的專案。但這個問題卻一直留在我的腦子裡,揮之不去。

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

[[email protected] ~]# vim 1.txt

Shell
123 111133335555

[[email protected] ~]# vim 2.txt

Shell
123456 111122223333444455556666

[[email protected] ~]# vim test.sh

Shell
12345 #!/bin/bashcat1.txt|whilereaduserId;dogrep$userId2.txtdone

結果,發現居然可以輸出結果!證明這系統沒有問題啊!於是再一次測試了一下昨天的指令碼,發現還是無法輸出。

於是使用 -x 引數 除錯一下指令碼:

先修改指令碼程式碼:

Shell
123456 #!/bin/bashcatuserid.txt|whilereaduserId;dogrep$userIdrecord.txtsleep3done

然後,帶 -x 引數執行:

Shell
1234567891011 [root@localhost~]#  sh -x test+catuserid.txt+readuserId+grep$'0001\r'record.txt+sleep3+readuserId+grep$'0003\r'record.txt+sleep3+readuserId+grep$'0005\r'record.txt+sleep3

難怪找不到,grep 的變數已經變了!0001 變成了 $'0001\r' !

看到\r,立馬想到是文字中的換行符,可為毛會輸出換行符呢?想到部落格以前寫的《Linux 終端:用 cat 命令檢視不可見字元》,繼續改了一下程式碼:

Shell
123456 #!/bin/bashcat-Auserid.txt|whilereaduserId;dogrep$userIdrecord.txtsleep3done

執行後恍然大悟:

Shell
1234567891011 [root@localhost~]#  sh -x test+cat-Auserid.txt+readuserId+grep'0001^M$'record.txt+sleep3+readuserId+grep'0003^M$'record.txt+sleep3+readuserId+grep'0005^M$'record.txt+sleep3

原來是 dos 下的文字格式,問了下同事,他還真是從 Windows 下導過來的! — —||

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

所以解決上述問題,就很明瞭了,要麼轉換 userid.txt 的換行格式,要不就修改程式碼,去掉多餘的字元!

試了下轉換格式,發現居然轉換不成功,可能是我沒找對方法,暫時先不折騰了!

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

Shell
1234567 #!/bin/bashcat-Auserid.txt|whilereaduserId;do#利用cut命令取出 ^ 之前的數字部分:id=`echo$userId|cut-d"^"-f1`grep$idrecord.txtdone

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

網上那些問 grep 無法搜尋變數的朋友,趕緊看看是不是文字格式造成的!現在,讓我很納悶的是,為毛在另一臺 centos 系統可以直接 grep??為什麼在 SUSE 系統就不行?

如果和發行版沒關係的話,那造成 2 個不同結果的原因就只有一個:在我用 sz+rz 命令將所有文字傳送到 centos 的過程中,檔案很可能被自動轉格式了!好吧,具體就不深究了,有興趣的可以試試看。