【问题标题】:Grep list (file) from another file来自另一个文件的 Grep 列表(文件)
【发布时间】:2023-03-31 02:39:01
【问题描述】:

我是 bash 新手,正在尝试从文件中提取模式列表:

文件1.txt

ABC
BDF
GHJ

base.csv(尝试用逗号分隔和制表符分隔)

line 1,,,,"hfhf,ferf,ju,ABC"
line 2 ,,,,,"ewy,trggt,gtg,ABC,RFR"
line 3 .."himk,n,hn.ujj., BDF"

建议的输出很像

ABC
line 1..
line 2..(whole lines)
BDF
line 3..

文件 1 中的每个模式以此类推

我尝试的代码是:

#!/bin/bash
for i in *.txt -# cycle through all files containing pattern lists
do
for q in "$i"; # # cycle through list
do
echo $q >>output.${i}; 
grep -f "${q}" base.csv >>output.${i};
echo "\n";
done
done

但输出只是文件名,然后是一些没有模式名称的字符串列表,例如

File1.txt
line 1...
line 2... 
line 3..

所以我不知道每个字符串属于什么模式,必须手动检查和分配。你能指出我的错误吗?谢谢!

【问题讨论】:

    标签: bash grep


    【解决方案1】:

    grep 可以一次处理多个文件,然后有一个吸引人的额外好处是可以指出它在哪个文件中找到了匹配项。

    grep -f File1.txt base.csv >output.txt
    

    不清楚你希望内循环做什么;它一次只会循环一个标记,所以它根本不是一个循环。

    如果您希望按模式对输出进行分组,这里有一个 for 循环,它一次查找一个模式:

    while read -r pat; do
        echo "$pat"
        grep "$pat" *.txt
    done <File1.txt >output.txt
    

    但解决此问题的最有效方法是编写一个简单的 Awk 脚本,该脚本一次处理所有输入文件,并在打印之前对匹配项进行分组。

    另一个问题是锚定。 grep "ABC" 将在 123DEABCXYZ 中找到匹配项;这是你想要避免的事情吗?您可以改进正则表达式,或者再次使用 Awk,它可以让您更好地控制在结构化行中查找匹配项的确切位置。

    awk '# Read patterns into memory
        NR==FNR { a[++i] = $1; next }
        # Loop across patterns
        { for(j=1; j<=i; ++j)
            if($0 ~ a[j]) {
                print FILENAME ":" FNR ":" $0 >>output.a[j]
                next }
        }' File1.txt base.csv
    

    【讨论】:

      【解决方案2】:

      您实际上并不是在读取文件,您只是在处理文件名。试试这个:

      #!/bin/bash
      for i in *.txt # cycle through all files containing pattern lists
      do
        while read -r q # read file line by line
        do
          echo "$q" >>"output.${i}" 
          grep -f "${q}" base.csv >>"output.${i}"
          echo "\n"
        done < "${i}"
      done
      

      【讨论】:

        【解决方案3】:

        这是一个将file2中的单词(split,逗号分隔,引号和空格去掉)分隔到一个数组(word[])并将记录名称(line 1等)存储到它以逗号分隔:

        awk '
        NR==FNR {
            n=split($0,tmp,/[" ]*(,|$)[" ]*/)                                  # split words
            for(i=2;i<=n;i++)                                                  # after first
                if(tmp[i]!="")                                                 # non-empties
                    word[tmp[i]]=word[tmp[i]] (word[tmp[i]]==""?"":",") tmp[1] # hash rownames
            record[tmp[1]]=$0                                                  # store records
            next
        }
        ($1 in word) {                                                         # word found
            n=split(word[$1],tmp,",")                                          # get record names
            print $1 ":"                                                       # output word
            for(i=1;i<=n;i++)                                                  # and records
                print record[tmp[i]]
        }' file2 file1
        

        输出:

        ABC:
        line 1,,,,"hfhf,ferf,ju,ABC"
        line 2 ,,,,,"ewy,trggt,gtg,ABC,RFR"
        BDF:
        line 3 .."himk,n,hn.ujj., BDF"
        

        【讨论】:

          【解决方案4】:

          感谢您的帮助,我的朋友们。 尝试了上述两种变体,但不断收到各种错误(预期为“do”)或行为不端(获取模式块的名称,例如 ABC、BDF,但没有行。 放弃了一段时间,然后最终尝试了另一种方式 虽然基本目标是循环浏览模式列表文件,在大文件中搜索模式并从找到的行中写出特定列 - 我只是写了

          for *i in *txt  # cycle throughfiles w/ patterns
          do
            grep -F -f "$i" bigfile.csv >> ${i}.out1   #greps all patterns from current file
            cut -f 2,3,4,7 ${i}.out1>> ${i}.out2   # cuts columns of interest and writes them out to another file
          done
          

          我知道应该使用一些花哨的管道功能来改进这段代码,但它可以完美地工作,希望它能帮助遇到类似情况的人。您可以按照我最初的要求轻松添加一些回声来写出模式列表名称

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-08-23
            • 2011-04-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多