5

grep无法查找shell传过来的变量?先注意一下文本格式吧!

 3 years ago
source link: https://zhang.ge/4703.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
grep无法查找shell传过来的变量?先注意一下文本格式吧! | 张戈博客
Jager · 11月15日 · 2014年shell · shell练习脚本 · shell脚本 11370次已读

昨天,同事告诉我发现一个诡异的问题,grep无法搜索shell中的变量,着实很惊讶。到他所说的服务器上试了下,还真是不行!

大概就是这样一个要求:

①、有个文本为userid.txt,里面每一行一个用户id,类似如下:

②、另外还有一个文本为record.txt,里面是所有用户的操作记录,一行一条,并且包含有id,类似如下:

[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

③、现在他要求循环取出userid.txt中每一行ID值,然后去record.txt去查找并保存结果。

实现这个需求原本很简单,根本难不倒他,只要使用while read + grep 就能搞定。可问题是明明record.txt里面包含这些id,却无法输出结果??

我顺便写了一个测试脚本测试了下:

#!/bin/bash
while read userId;
echo $userId
grep $userId record.txt
done <userid.txt

发现脚本可以打印echo $userId,却无法grep到??而实际上record.txt里面是有这个id的!还真诡异!

先百度搜索了一下【grep 无法搜索变量】,还真有不少类似问题,比如:http://bbs.chinaunix.net/thread-123113-1-1.html

根据经验,对于这种诡异的问题,我首先会想到是不是系统有问题,要是系统有问题你怎么折腾都是错!

于是把他的文件拷贝到其他服务器,发现居然可以了!!!难道真是系统问题么?

第一台是SUSE Linux,第二台是Centos,难道和系统发行版有关系?

后来,同事在第二台服务器上完成了他的项目。但这个问题却一直留在我的脑子里,挥之不去。


今天,我决定再次研究下这个问题,看看是不是有其他原因。我先在那台SUSE Linux上,手工编写所需文件:

[root@localhost ~]# vim 1.txt

[root@localhost ~]# vim 2.txt

[root@localhost ~]# vim test.sh

#!/bin/bash
cat 1.txt|while read userId;
grep $userId 2.txt

结果,发现居然可以输出结果!证明这系统没有问题啊!于是再一次测试了一下昨天的脚本,发现还是无法输出。

于是使用 -x 参数 调试一下脚本:

先修改脚本代码:

#!/bin/bash
cat userid.txt|while read userId;
grep $userId record.txt
sleep 3

然后,带 -x 参数执行:

[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的变量已经变了!0001变成了 $'0001\r' !

看到\r,立马想到是文本中的换行符,可为毛会输出换行符呢?想到博客以前写的《Linux终端:用cat命令查看不可见字符》,继续改了一下代码:

#!/bin/bash
cat -A userid.txt|while read userId;
grep $userId record.txt
sleep 3

执行后恍然大悟:

[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下导过来的! — —||

也就是说,userid.txt这个文本的换行符是Windows格式,在Linux下读取会带有^M。

所以解决上述问题,就很明了了,要么转换userid.txt的换行格式,要不就修改代码,去掉多余的字符!

试了下转换格式,发现居然转换不成功,可能是我没找对方法,暂时先不折腾了!

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

#!/bin/bash
cat -A userid.txt|while read userId;
#利用cut命令取出 ^ 之前的数字部分:
id=`echo $userId | cut -d"^" -f1`
grep $id record.txt

好了,搞了半天原来是dos和unix的换行符问题!o(︶︿︶)o 唉!还是经验不足啊!

网上那些问grep无法搜索变量的朋友,赶紧看看是不是文本格式造成的!现在,让我很纳闷的是,为毛在另一台centos系统可以直接grep??为什么在SUSE系统就不行?

如果和发行版没关系的话,那造成2个不同结果的原因就只有一个:在我用sz+rz命令将所有文本传送到centos的过程中,文件很可能被自动转格式了!好吧,具体就不深究了,有兴趣的可以试试看。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK