grep無法查詢shell傳過來的變數?先注意一下文字格式吧!
昨天,同事告訴我發現一個詭異的問題,grep 無法搜尋 shell 中的變數,著實很驚訝。到他所說的伺服器上試了下,還真是不行!
大概就是這樣一個要求:
①、有個文字為 userid.txt,裡面每一行一個使用者 id,類似如下:
Shell12345 | 00010003000500070009 |
②、另外還有一個文字為 record.txt,裡面是所有使用者的操作記錄,一行一條,並且包含有 id,類似如下:
Shell123456789 | [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 |
③、現在他要求迴圈取出 userid.txt 中每一行 ID 值,然後去 record.txt 去查詢並儲存結果。
實現這個需求原本很簡單,根本難不倒他,只要使用 while read + grep 就能搞定。可問題是明明 record.txt 裡面包含這些 id,卻無法輸出結果??
我順便寫了一個測試指令碼測試了下:
Shell123456 | #!/bin/bashwhilereaduserId;doecho$userIdgrep$userIdrecord.txtdone<userid.txt |
發現指令碼可以列印 echo $userId,卻無法 grep 到??而實際上 record.txt 裡面是有這個 id 的!還真詭異!
根據經驗,對於這種詭異的問題,我首先會想到是不是系統有問題,要是系統有問題你怎麼折騰都是錯!
於是把他的檔案拷貝到其他伺服器,發現居然可以了!!!難道真是系統問題麼?
第一臺是 SUSE Linux,第二臺是 Centos,難道和系統發行版有關係?
後來,同事在第二臺伺服器上完成了他的專案。但這個問題卻一直留在我的腦子裡,揮之不去。
今天,我決定再次研究下這個問題,看看是不是有其他原因。我先在那臺 SUSE Linux 上,手工編寫所需檔案:
[[email protected] ~]# vim 1.txt
Shell123 | 111133335555 |
[[email protected] ~]# vim 2.txt
Shell123456 | 111122223333444455556666 |
[[email protected] ~]# vim test.sh
Shell12345 | #!/bin/bashcat1.txt|whilereaduserId;dogrep$userId2.txtdone |
結果,發現居然可以輸出結果!證明這系統沒有問題啊!於是再一次測試了一下昨天的指令碼,發現還是無法輸出。
於是使用 -x 引數 除錯一下指令碼:
先修改指令碼程式碼:
Shell123456 | #!/bin/bashcatuserid.txt|whilereaduserId;dogrep$userIdrecord.txtsleep3done |
然後,帶 -x 引數執行:
Shell1234567891011 | [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 命令檢視不可見字元》,繼續改了一下程式碼:
Shell123456 | #!/bin/bashcat-Auserid.txt|whilereaduserId;dogrep$userIdrecord.txtsleep3done |
執行後恍然大悟:
Shell1234567891011 | [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 的換行格式,要不就修改程式碼,去掉多餘的字元!
試了下轉換格式,發現居然轉換不成功,可能是我沒找對方法,暫時先不折騰了!
直接如下修改程式碼,就搞定了:
Shell1234567 | #!/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 的過程中,檔案很可能被自動轉格式了!好吧,具體就不深究了,有興趣的可以試試看。