Grep多个文件并将输出保存到不同的列

时间:2018-03-26 04:57:30

标签: awk command-line grep

使用mac命令行,我想grep多个文件并将输出保存到不同的列。

以下是我的一个文件的示例ncbi.nlm.nih.gov/nuccore/NZ_AP013294(点击'发送到','文件'保存格式为'完整的genbank文件')。我有~2000个。我只想要LOCUS(这对于每个文件都是唯一的,并且总是有一个)然后每次都有tRNA-,例如tRNA-Glu(整个文件中出现tRNA-,其中可能有0到200个)。

当我在其中一个文件上执行此操作时

grep -e "LOCUS-" -e "tRNA-" *.gbff > output.txt

但我希望output.txt文件包含列,每个*.gbff文件一个:

LOCUS XXXX     LOCUS XXXX
tRNA-Glu        tRNA-Asn
tRNA-Ser        tRNA-Ile
                tRNA-Glu

...等

4 个答案:

答案 0 :(得分:2)

更新了答案

我认为我的原始方法对于您拥有的文件数量而言资源过于密集,因此这是一个不太密集的版本:

#!/bin/bash

# Don't barf of no matching files, and allow upper and lower case
shopt -s nullglob nocaseglob

# Loop through all ".txt" files whose names start with "seq"
j=0
for f in seq*txt; do
   # Generate output file name
   printf -v out "Z%05d.tmp" $j
   grep -E "LOCUS\s*NZ_AP013294|tRNA" "$f" > "$out"
   ((j=j+1))
done

# Paste all output files together in columns
paste Z*tmp > result.txt

# Remove temp files
rm Z*tmp

我只命名所有以" Z"开头的临时文件。因此它们只会在文件浏览器的最后显示。

因此,将上述内容保存在名为" go"的文件中。在您的HOME目录中,然后使用以下命令使其可执行:

chmod +x $HOME/go

然后你可以通过以下方式在任何目录中运行它:

cd some/place/where/your/files/are
$HOME/go

原始答案

我认为这给了你想要的东西:

parallel 'grep "term" {} > {#}.tmp' ::: *txt ; paste *tmp ; rm *tmp

示例输出

term1   term1
term3   term2
        term3

那说...... "在名称以term结尾的所有文件中查找txt,保存1.tmp中第一个的输出,第二个在2.tmp等等。最后,将所有临时文件粘贴到列中并将其删除。"

您需要知道,使用 GNU Parallel {}代表"当前参数/文件" 和{{ 1}}代表"当前作业编号" ,最后{#}将参数与要应用的命令分开。

您也可以在没有临时文件的情况下执行此操作。使用 GNU Parallel 作业编号为:::输出的每一行添加前缀,然后通过 Perl 中的批次删除作业编号并将其替换为8 *很多空间:

grep
所有Mac都附带

Perl

对于任何感兴趣的人,这是Schwartzian Transform或Lisp decorate-sort-undecorate 习语的变体。

我使用自制安装 GNU Parallel

parallel --tag-string {#} 'grep "term" {}' ::: *txt | perl -plne 's/^(\d+)\s*/" " x (8*($1-1))/e'

term1
term3
        term1
        term2
        term3

虽然它也可以在没有自制的情况下非常简单地安装,因为 Perl 脚本,并且所有Mac都附带 Perl

brew install parallel

答案 1 :(得分:1)

你的问题不清楚,但考虑到你的要求可能的解释,这可能是你想要的:

awk '
/LOCUS/ {
    locus[++numCols] = $0
}
/tRNA/ {
    rnas[++rowNrs[numCols],numCols] = $0
    numRows = (rowNrs[numCols] > numRows ? rowNrs[numCols] : numRows)
}
END {
    for (colNr=1; colNr<=numCols; colNr++) {
        printf "%s%s", locus[colNr], (colNr<numCols ? OFS : ORS)
    }
    for (rowNr=1; rowNr<=numRows; rowNr++) {
        for (colNr=1; colNr<=numCols; colNr++) {
            printf "%s%s", rnas[rowNr,colNr], (colNr<numCols ? OFS : ORS)
        }
    }
}
' *.txt

当然未经测试,因为您没有提供样本输入/输出,我们可以测试。

如果那不是你想要的,那么你想要的任何东西都同样微不足道但是你必须首先告诉/告诉我们你的问题是什么,以便为它找到解决方案。

答案 2 :(得分:1)

使用awk的模式匹配来查找单个LOCUS和任何tRNA提及。

使用awks字段拆分作为第二项

免费获取locus登录

将tRNA产品(如果有的话)拆分成引号并将它们与基因座加入相关联。

跟踪一个基因座的最大tRNA数量,这将是输出的行数(加上标题)

在处理命令行上给出的所有文件中的所有GenBank记录之后。

输出每个基因座的加入作为标题 然后为每一行尽可能  输出在其基因座加入下相关的任何tRNA产物。

脚本:

#! /usr/local/bin/gawk -f

/^LOCUS       /{RefSeq = $2}

/^                     \/product="tRNA-/{
    split($1, tRNA, "\"");
    head[RefSeq]++;  
    LOCUS[RefSeq,head[RefSeq]] = tRNA[2]
    if(head[RefSeq] > rows)
        rows = head[RefSeq] 
}

END{
    # to ensure constant order
    cols = asorti(head)
    for(i=1;i<=cols;i++)
        header = header "|" head[i]
    print substr(header, 2)

    for(r=1; r<=rows; r++){
        row = ""
        for(c=1; c<=cols; c++)
            row = row "|" LOCUS[head[c],r]
        print substr(row, 2)
    }
}

指南 注意:我抓到的gbff每个文件都有多个GenBank记录

 ls -l

-rw-r--r-- 1 tomc tomc 1724943 Mar 31 23:21 bacteria.24.genomic.gbff
-rw-r--r-- 1 tomc tomc 3216313 Mar 31 23:53 bacteria.431.genomic.gbff
-rwxr-xr-x 1 tomc tomc     487 Mar 31 23:51 locus_trna_transpose.awk

结果: 注意:使用管道作为字段分隔符以便于查看

./locus_trna_transpose.awk bacteria*.gbff
 NZ_AWIQ01000161|NZ_AWIQ01000167|NZ_AWIQ01000183|NZ_AWKN01000226|NZ_AWKN01000319|NZ_AWLJ01000031|NZ_AWLJ01000043|NZ_AWLJ01000050|NZ_JORA01000025|NZ_JORA01000026|NZ_JORA01000030|NZ_JORA01000031|NZ_JORA01000032|NZ_JORA01000034|NZ_JORA01000036|NZ_JORA01000037
tRNA-binding|tRNA-Arg|tRNA-Met|tRNA-Asn|tRNA-binding|tRNA-Val|tRNA-Leu|tRNA-binding|tRNA-Pro|tRNA-Val|tRNA-Arg|tRNA-Arg|tRNA-Met|tRNA-Phe|tRNA-Met|tRNA-Met
|||||tRNA-Val|||tRNA-Arg|tRNA-Val|tRNA-Arg|tRNA-Arg|tRNA-Met||tRNA-binding|tRNA-Leu
||||||||tRNA-Ala|tRNA-Val||tRNA-Ser|tRNA-Met|||
||||||||tRNA-Ala|tRNA-Val|||tRNA-Gly|||
||||||||tRNA-Ala|tRNA-Lys|||tRNA-modifying|||
||||||||tRNA-Ala|||||||

对于那些一起玩的人来说, 这些输入文件从

中抓取得很小

ftp://ftp.ncbi.nlm.nih.gov/refseq/release/bacteria/

答案 3 :(得分:1)

此类处理实际上超出了grep的功能。你最好创建一个完全符合你想要的小型自定义脚本。我会使用pythonpandas来完成任务。这是一个实现,基于我目前对您的描述的理解。

代码

import re
import sys
import pandas as pd

# Regular expressions; adjust as necessary
regex_locus = re.compile('LOCUS\s+(\S+)')
regex_trna  = re.compile('"(tRNA-.*)"')

# Aggregate results in a dataframe
df = pd.DataFrame()

total_files = len(sys.argv[1:])

# Iterate over the files given on the command line
for index, file in enumerate(sys.argv[1:]):

    print("Processing {:4d}/{:4d}: {}".format(index + 1, total_files, file))

    # Per file variables.
    locus = None
    trna  = []

    # Open the file for reading
    with open(file) as fd:

        # Find LOCUS value
        for line in fd:
            match = regex_locus.search(line)

            if match:
                locus = match.group(1)

                # Done with this section
                break

        # Find tRNA values
        for line in fd:
            match = regex_trna.search(line)

            if match:
                trna.append(match.group(1))

    # Done with this file
    if locus is not None:
        # Add the entry for this file. Convert the list to a pandas Series to account for differing lengths.
        df[locus] = pd.Series(trna)

# Write out the final DataFrame as csv
df.to_csv('output.csv', index=False)

# And as text...
with open('output.txt', 'w') as fd:
    df.to_string(fd, index=False)

注释

  • 我假设LOCUS行始终出现在tRNA值之前。这似乎是您的示例文件中的格式。
  • 代码生成output.csvoutput.txt。输出格式基本上是免费的,因为数据在DataFrame中。
  • 如果脚本名为build_table.py,则会将其调用为:python build_table.py *.gbff