美文网首页
Linux中的文件内查找小技巧

Linux中的文件内查找小技巧

作者: 鹿无为 | 来源:发表于2020-02-16 14:21 被阅读0次

写在前面的废话

这一周我为自己的马虎付出了严重的代价!!!
每天十几个小时一直在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

相关文章

  • Linux中的文件内查找小技巧

    写在前面的废话 这一周我为自己的马虎付出了严重的代价!!!每天十几个小时一直在debug……以后写代码之前一定要拜...

  • Linux中的文件查找技巧

    前言 Linux常用命令中,有些命令可以帮助我们查找二进制文件,帮助手册或源文件的位置,也有的命令可以帮助我们查找...

  • Linux命令之文件管理 (四十九)

    Linux whereis命令Linux whereis命令用于查找文件。 该指令会在特定目录中查找符合条件的文件...

  • Linux中常用的查找命令

    linux 中常用的查找文件和文件中字符串的操作: 在某个路径下查找文件 例如在 /etc 中查找 "*.log"...

  • Linux find and grep

    linux下的find文件查找命令与grep文件内容查找命令 linux下的find文件查找命令与grep文件内容...

  • linux下的find文件查找命令与grep文件内容查找命令

    linux下的find文件查找命令与grep文件内容查找命令 在使用linux时,经常需要进行文件查找。其中查找的...

  • linux下的find文件查找命令与grep文件内容查找命令

    linux下的find文件查找命令与grep文件内容查找命令 在使用linux时,经常需要进行文件查找。其中查找的...

  • Linux查找命令

    本文介绍Linux中的查找功能 1. locate 查找文件 命名格式:locate 文件名 查找原理:locat...

  • 文件名的查找

    Linux会将系统内的所有文件都记录在一个数据库文件中. whereis和locate是利用数据库查找, 所以相当...

  • week(4)

    Linux查找目录或文件 查找目录:find /(查找范围) -name '查找关键字' -type d 查找文件...

网友评论

      本文标题:Linux中的文件内查找小技巧

      本文链接:https://www.haomeiwen.com/subject/dtramctx.html