【问题标题】:While loop to break when pattern is found in all files?当在所有文件中找到模式时循环中断?
【发布时间】:2021-12-17 02:32:42
【问题描述】:

下面的代码在多个文件中搜索一组模式(包含在 $snps 变量中)($file 变量用于以 snp_search.txt 结尾的文件)并输出每个 snp 是否在每个文件中的长列表.

目的是找到所有文件中的几个SNP。

有没有办法将下面的代码嵌入到 while 循环中,以便它继续运行,直到找到所有文件中的 SNP 并在它找到时中断?否则我必须手动检查日志文件。

for snp in $snplist; do
   for file in *snp_search.txt; do

     if grep -wq "$snp" $file; then
       echo "${snp} was found in $file" >> ${date}_snp_search.log; else
       echo "${snp} was NOT found in $file" >> ${date}_snp_search.log
     fi
   done
done

【问题讨论】:

  • 请使用SNPs 的示例列表和*.txt 文件中的几行(与示例SNP 值匹配和不匹配的行)更新问题

标签: linux bash loops for-loop while-loop


【解决方案1】:

您可以使用grep 搜索所有文件。如果文件名不包含换行符,则可以直接计算匹配文件的数量:

#! /bin/bash
files=(*snp_search.txt)
count_files=${#files[@]}
for snp in $snplist ; do
    count=$(grep -wl "$snp" *snp_search.txt | wc -l)
    if ((count == count_files)) ; then
        break
    fi
done

对于包含换行符的文件名,您可以为每个 $snp 输出不带文件名的第一个匹配行并计算行数:

count=$(grep -m1 -hw "$snp" *snp_search.txt | wc -l)

【讨论】:

  • 您好 choroba,非常感谢您的回复!如果我希望您的代码打印找到的 SNP,那么如果我将 echo "The SNP $snp was found in all files" >>out.log 放在 "fi" 下面,它会起作用吗?
  • @SpencerK:没错。
【解决方案2】:

假设:

  • 输入文件的单行中可能存在多个 SNP
  • 将打印所有文件中存在的所有 SNP列表(OP提到了矛盾的陈述:find several SNPs that are in all of the files vs break when one SNP is found in all files

示例输入(如果 OP 使用示例数据更新问题,则会更新):

$ cat snp.dat
ABC
DEF
XYZZ

$ cat 1.snp.search.txt

ABCD-XABC
someABC_stuff
ABC-
de-ABC-
de-ABC
DEFG
zDEFG
.DEF-xyz
abc-DEF
abc-DEF-ABC-xyz

$ cat 2.snp.search.txt
ABC

一个GNU awk 的想法需要一次通过每个输入文件:

awk '
FNR==NR { snps[$1]=0; next }                        # load 1st file into array; initialize counter (of files containing this snp) to 0

FNR==1  { filecount++                               # 1st line of 2nd-nth files: increment counter of number of filds
          delete to_find                            # delete our to_find[] array
          for (snp in snps)                         # make a copy of our master snps[] array ...
               to_find[snp]                         # storing copy in to_find[] array
        }

        { for (snp in to_find) {                    # loop through list of snps 
              if ($0 ~ "\\y" snp "\\y") {           # if current line contains a "word" match on the current snp ...
                 snps[snp]++                        # increment our snp counter (ie, number of files containing this snp)
                 delete to_find[snp]                # no longer need to search current file for this particular snp
#                break                              # if line can only contain 1 snp then uncomment this line
              }
          }

          for (snp in to_find)                      # if we still have an snp to find then ...
              next                                  # skip to next line else ...
          nextfile                                  # skip to next file
        }

END     { PROCINFO["sorted_in"]="@ind_str_asc"
          for (snp in snps)
              if (snps[snp] == filecount)
                 printf "The SNP %s was found in all files\n", snp
        }
' snp.dat *.snp.search.txt 

注意事项:

  • PROCINFO["sorted_in"]="@ind_str_asc" 选项需要GNU awk 才能对snps[] 数组索引进行排序;如果GNU awk 不可用,或者输出消息的顺序不重要,则可以从代码中删除此命令
  • 因为我们只在打印 all 个出现在 all 文件中的 SNP 时才处理每个输入文件(即,我们不知道 SNP 是否存在于所有文件中)文件,直到我们处理完最后一个文件,所以不妨打印所有文件中存在的所有 SNP)
  • 应该比需要对每个输入文件进行多次扫描的进程更快(尤其是对于较大的文件和/或大量 SNP)

这会生成:

The SNP ABC was found in all files

【讨论】:

    猜你喜欢
    • 2019-04-02
    • 1970-01-01
    • 2017-08-24
    • 2020-02-26
    • 2022-10-14
    • 2021-11-27
    • 2020-08-23
    • 2010-10-07
    • 2021-11-26
    相关资源
    最近更新 更多