Linux中的文件内查找小技巧

写在前面的废话

这一周我为自己的马虎付出了严重的代价!!!
每天十几个小时一直在debug……以后写代码之前一定要拜拜雍正,专治八阿哥(bug)


image.png

虽然debug让我无心其他事情,但是咱说好的周更不能断(其实是我找到了bug,想写篇文章压压惊)

太长不看系列

  • 最粗鲁的办法:grep -f (慢,内存需求太大)
  • 比较省事的办法:R的merge函数 (较快,但是内存需求贼大)
  • 比较机智的办法:字典/哈希(很快,Python里面叫作字典,Perl里面似乎叫作哈希,对于不会这两门语言的同学友好性太差)
  • 稳如老狗的办法:awk命令 (也是依赖字典方法,速度快,操作简单,深得吾心)


    image.png

废话超多系列

我相信你们和我一样,有时需要知道文件A中有哪些行出现在文件B中。说起来有点绕,直接举个例子可能会更通俗易懂一些:

> cat A.txt
Hello
Thank you
Thank you very much
> cat B.txt
Hello
Welcome to
Beijing

文件A中有哪些行在文件B中也出现过,这个例子比较简单,我们直接就能看出A.txt中的Hello在B.txt文件中出现。

但是当文件较大时怎么办呢?一百行的话,你也许还可以试试 肉眼去观察,一旦行数上万,就必须借助计算机帮助我们完成这些事情了

不瞒你说,我之前查找的两个文件,一个几百万行,另一个上千万行,为了找一个合适的方法可是苦恼了很久

最粗鲁的办法:grep

grep方法比较粗鲁,但针对比较小的文件,我还是很喜欢用它的。因为它只需要敲六个字符,真的节省体力。
cat -f A.txt B.txt : 可以把B文件中存在于A文件中的行输出,具体操作如下

image.png

如果你使用了-v参数,则可以进行另一个骚操作,输出只存在与B文件而不存在与A文件中的行。但是这个方法有一些缺点,比如:

  • 不能分字段查找(比如A文件的第二列信息,是否在B文件中的第三列信息中出现)
  • 针对大文件,耗时长且内存消耗大(时间我没有专门统计过,但是在运行这个命令的时候内存倒是溢出过,如下图)


    image.png

比较省事的办法:R的merge函数

做生信的同学,你可以不会Python,你可以不会Perl,但是R你总要会一点吧……

当我们在R中合并文件时,我们经常会用到merge()函数,它可以根据两文件中指定的列进行合并,对文件取交集。换个角度想想,这个取交集的操作不就是找把B文件中存在于A文件中的行么。

这里,因为篇幅问题,我就不介绍merge函数是如何使用的了。这个函数的原理我自己也不是很懂,只是知道是它用空间换时间,速度很快,但是内存消耗是真的大

下面是我对两个几百兆的文件merge时的报错信息,可以看到内存溢出的那是相当严重


image.png

比较机智的办法:字典/哈希

如果你学过Python,一定知道dict()字典。这个方法是真的快,就和查字典一样,不存在遍历的问题。这里推荐阅读廖雪峰老师关于字典的介绍,我自己的语言功底很难三两句话把这个名词解释清楚。

Python里面叫作字典,Perl里面似乎叫作哈希

但是该方法对于不会这两门语言的同学友好型太差,我只是想比对个文件,你却让我从头开始学一门编程语言???(内心:你这是想要我死????)


image.png

稳如老狗的办法:awk命令

铺垫了这么多,终于可以扯到重点上了。awk/sed/grep可以说是shell中处理数据的三剑客,我们大部分的数据清洗问题,都可以使用这三个方法解决。

听起来这么牛,但是我们大部分人只会其基本操作,稍微复杂一点就会触碰到我们的知识盲区……


image.png

没关系,饭要一口一口吃,毕竟肥肉不是一天长成的,头发也不是一天就掉光的……

这里说个实话,希望不会挨打

这里简单介绍一下awk的一些参数,只介绍稍后用到的参数,想了解更多,可以自行搜索学习

  • FNR:各文件分别计数的行号。当awk命令后面跟了不止一个文件时,每读入一个新文件,行号就要从头开始计算。
  • NR:已经读出的记录数,就是行号,从1开始,不断累加,读入新文件也不会从头开始计算

    比如 awk命令之后跟了两个文件,分别有3行和5行,那么FNR的值依次时1,2,3,1,2,3,4,5;而NR的值则是1,2,3,4,5,6,7,8

  • $0表示读取的文件某一行的所有内容,$1表示某一行的第一列,$2表示某一行的第二列,以此类推
  • '[]':数组,比如a[$0]

介绍了这么多,我应该如何使用这些参数呢?

awk 'NR==FNR {a[$0]} NR>FNR&&!($0 in a){print $0}' A.txt B.txt

这里的NR==FNR,表示当前读取的是第一个文件A.txt的内容,这个时候创建一个数组,将第一个文件的每一行内容都作为一个key值输入,如果不存在这个a[$0]变量,则创建一个。通过这个方法,我们可以把文件A.txt的所有内容逐行放入数组变量a中。

接着NR>FNR表示,当前读取的不是第一个文件(即开始读取B.txt文件)。!($0 in a)表示当前读入的行,不存在之前的a数组中(即:B.txt文件中不存在于A.txt文件中的行)。中间的&&表示前后两个条件都要满足,若满足则执行print $0命令。

最终输出的结果将是只存在于B文件中,而不存在于A文件中的行。除此之外,我们可以指定比较两个文件中的特定列,比如:

awk 'NR==FNR {a[$3]} NR>FNR&&!($2 in a){print $0}' A.txt B.txt

以上命令表示,我想找出只存在于B文件中第二列,而不存在于A文件中第三列的字段,若存在这样的字段,则将B文件中该字段所在的行打印输出。

这个方法,速度快,容易上手,基本上你会用Linux就可以。既然提到了awk命令,那就再说一个骚操作:文件去重!!!

好吧,我知道一旦说去重,你首先想到的一定是以下两条命令:

  1. sort A.txt | uniq
  2. sort -u A.txt

这个方法固然是好,但是sort命令排序十分耗时。处理小文件时我们可能体会不到,但是一旦遇到上百万行的文件,光是等待时间就够我们喝一壶茶了。这个时候awk命令就体现出其重要性了。命令如下:

awk '!a[$0]++' A.txt

这里不讲太多,简单说一下这个命令执行的步骤:

  1. 首先执行a[$0],将输入文件的一整行当作数组a的key值
  2. 接着执行!a[$0],对a[$0]的值取反,如果a[0]返回值为0,则整个表达式`!a[0]`为1,执行awk的默认操作,打印输出这一行
  3. 最后是!a[$0]++,对a[$0]的值加1,因此当之后再遇到相同行时,!a[$0]会被看作是0,不hi行默认的打印操作

也许你觉得我讲的还是不够清楚,那么这里给你推荐一个问答,里面的第一个回答(最高赞)将这个去重的逻辑讲的十分清楚。

一点题外话

大部分做生信的人,对于算法都是一知半解,只求解决问题不求代码优美。但写代码,我们毕竟不是专业的。我们的终极目的是解决生物学问题,而不是过多的纠结代码的优美性。

代码写的再好看,解决不了问题,依然发不了sci

另外代码不要晚上写,一个原因是晚上写代码容易出bug(这是一个涉及玄学的话题),另外一个原因就是熬夜令人头秃。

最近头有点凉,也不知道是天气冷了,还是头发秃了

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容