【问题标题】:Finding a numbered file by range that falls within it - pattern matching - from command line按范围查找编号文件 - 模式匹配 - 从命令行
【发布时间】:2023-03-04 06:31:01
【问题描述】:

带有分块文件(>1000 个文件)的文件夹,格式为:

text_chr[A]_[numberB]_[numberC]_text.vcf.gz 

numberB 到 numberC 是一个范围。

例子:

main_programme_ver2_chr1_1_1000000_VEPannot.vcf.gz 
main_programme_ver2_chr1_1000001_987325982_VEPannot.vcf.gz 
..
main_programme_ver2_chr2_1_875832_VEPannot.vcf.gz 
main_programme_ver2_chr2_875833_100098325_VEPannot.vcf.gz 
etc 

第 4 列包含基因名称的文件,染色体 (col1) 和坐标 (col2 和 3)(>20000 个条目),以下几行:

chr1 1000848 3959403 HAT1 
chr2 83523 85382 JKLP

格式:A B C Gene_name,B到C也是一个范围

关于该基因的信息位于文件夹 1 中的一个文件中,因此我需要在文件名范围内对基因位置进行模式匹配。例如,我想知道将包含基因HAT1 和JKLP 的文件,答案分别是main_programme_ver2_chr1_1000001_987325982_VEPannot.vcf.gz 和main_programme_ver2_chr2_1_875832_VEPannot.vcf.gz,目前我正在手动执行此操作。我需要将这些文件名输入到一些下游分析中。

所以我需要匹配A,然后从基因列表中选择包含B 到C 范围的块。

有没有办法从命令行执行此操作?

非常感谢

【问题讨论】:

    标签: linux bash command-line


    【解决方案1】:

    更新: OP 用一组更具代表性的*.vcf.gz 文件名更新了问题。

    此时我将假设文件名的格式为 ...

    some_text_chrXXX_number1_number2_more_text.vcf.gz
              ^^^^^^^^^^^^^^^^^^^^^^
    

    ...我们对这部分文件名感兴趣:chrXXX_number1_number2。

    在建议的代码(如下)中,我们将遍历这些文件名,将名称解析为块,然后处理这些块。我们将用于解析文件名的步骤:

    f=some_text_chrXXX_number1_number2_more_text.vcf.gz
    g=${f//*_chr/chr}                                    # strip off 'some_text_'
    h=${g//.vcf.gz}                                      # strip off '.vcf.gz'
    echo "f=${f}"
    echo "g=${g}"
    echo "h=${h}"
    
    IFS='_' read -r cx n1 n2 stuff <<< "${h}"            # break $h into 4 variables
    
    echo "cx=${cx}"
    echo "n1=${n1}"
    echo "n2=${n2}"
    echo "stuff=${stuff}"                                # catch all for rest of '$h'
    

    这会生成:

    f=some_text_chrXXX_number1_number2_more_text.vcf.gz
    g=chrXXX_number1_number2_more_text.vcf.gz
    h=chrXXX_number1_number2_more_text
    cx=chrXXX
    n1=number1
    n2=number2
    stuff=more_text
    


    假设:

    • this question 的 cmets 部分中散列的详细信息适用于此问题
    • 一个给定的基因可能会在file1 中出现多次
    • file1 中给定的数字范围可能匹配超过 1 个 *.vcf.gz 文件名
    • 所有感兴趣的文件都在当前目录中(OP 可以根据需要将适当的cd 命令添加到脚本中)

    样本数据:

    $ cat file1
    chr1 1000848 3959403 HAT1 
    chr2 83523 85382 JKLP
    chr3 20000 40000 STEV
    chrX 23456 78901 WXYZ
    
    $ ls -1v *vcf.gz
    main_programme_ver2_chr1_1_1000000_VEPannot.vcf.gz
    main_programme_ver2_chr1_1000001_987325982_VEPannot.vcf.gz  # match HAT1
    
    main_programme_ver2_chr2_1_875832_VEPannot.vcf.gz           # match JKLP
    main_programme_ver2_chr2_875833_100098325_VEPannot.vcf.gz 
    
    main_programme_ver2_chr3_1_25000_VEPannot.vcf.gz            # match STEV
    main_programme_ver2_chr3_25001_80000_VEPannot.vcf.gz        # match STEV
    main_programme_ver2_chr3_80001_100000_VEPannot.vcf.gz
    
    main_programme_ver2_chrX_100000_999999_VEPannot.vcf.gz
    

    使用一对bash 循环的一个想法:

    $ cat gene.bash
    #!/usr/bin/bash
    
    read -p "Gene to search for: " gene
    
    echo "+++++++++++ gene: ${gene}"
    
    found=0
    
    while read -r chr b c stuff                        # read fields from file1
    do
        for f in *_${chr}_*                            # for all files that match 'chr' string from file1 ...
        do
            g=${f//*_chr/chr}
            h=${g//.vcf.gz}
    
            IFS='_' read -r cx n1 n2 stuff <<< "${h}"  # break 'h' into chunks based on delimiter '_'
    
            # check each value from file1 (b,c) for inclusion in filename ranges (n1-n2)
    
            [[ "${b}" -ge "${n1}" ]] && [[ "${b}" -le "${n2}" ]] && echo "${f}" && found=1 && continue
            [[ "${c}" -ge "${n1}" ]] && [[ "${c}" -le "${n2}" ]] && echo "${f}" && found=1
        done
    
    done < <(grep -w "${gene}" file1)                  # search file1 for rows containing 'gene'
    
    [[ "${found}" -ne 1 ]] && echo "WARNING: no files found for gene = '${gene}'"
    

    测试运行:

    $ ./gene.bash
    Gene to search for: HAT1
    +++++++++++ gene: HAT1
    main_programme_ver2_chr1_1000001_987325982_VEPannot.vcf.gz
    
    $ ./gene.bash
    Gene to search for: JKLP
    +++++++++++ gene: JKLP
    main_programme_ver2_chr2_1_875832_VEPannot.vcf.gz
    
    $ ./gene.bash
    Gene to search for: STEV
    +++++++++++ gene: STEV
    main_programme_ver2_chr3_1_25000_VEPannot.vcf.gz
    main_programme_ver2_chr3_25001_80000_VEPannot.vcf.gz
    
    $ ./gene.bash
    Gene to search for: WXYZ
    +++++++++++ gene: WXYZ
    WARNING: no files found for gene = 'WXYZ'
    
    $ ./gene.bash
    Gene to search for: ZZZZ
    +++++++++++ gene: ZZZZ
    WARNING: no files found for gene = 'ZZZZ'
    

    【讨论】:

    • 是的,file1 通过最后一行 (done &lt; &lt;(grep -w "${gene}" file1) 被读入 while 循环;对于这个答案,我在代码中硬编码了文件名(file1),但您可以将文件名作为命令行参数传递,用户输入对提示的响应,或者从配置文件中读取...最适合您的要求的方法
    • 非常感谢您花时间回答。我理解这背后的原理,但实际的文件块看起来像这样:main_programme_ver2_chr22_2874210_2947732_VEPannot.vcf.gz(例如),我将如何调整你的脚本?
    • 答案基于您问题中的示例文件名;代码 - IFS='[_.]' read -r x a z stuff &lt;&lt;&lt; "${f}" - 根据 2 个分隔符 - _ 和 . 将文件名分成块 - 然后将这些块读入变量 x、a、z 和 stuff;对于chr1_1_1000000.vcf.gz => x=chr1 / a=1 / z=1000000 / stuff="vcf gz";如果您的实际文件名有更多块,则添加更多变量来存储这些块;或者,用 actual 文件名示例更新问题,让我们知道 ALL 文件名是否具有相同格式,我可以更新答案
    • 我已经编辑了问题并为我的愚蠢道歉!
    • 非常感谢您抽出宝贵时间提供帮助。这将节省无数时间!
    猜你喜欢
    • 2017-02-02
    • 2016-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多