Linux は、指定されたファイルセットからのみ文字列を検索します。

Linux は、指定されたファイルセットからのみ文字列を検索します。

1つのディレクトリに複数のファイルがあります。与えられた文字列で終わるすべての文字列を検索して見つけようとします。ディレクトリ内のすべてのファイルではなく、特定のファイル名セットのみを検索したいと思います。最後に、出力は、各ファイル名とそのファイルで見つかったセミコロンで区切られた文字列の発生回数でなければなりません。

単純化されたテストケースは次のとおりです。ディレクトリに5つのファイルがあります。

file.a.txt
file.b.txt
file.c.txt
file.d.txt
file.e.txt

searchFiles.txt上記のリストの最初の3つのファイル名を含むファイルもあります。だから、リストされているファイル名からのみ文字列を検索したいと思いますsearchFiles.txt

私は試した:

for i in $(cat searchFiles.txt); do grep -o '[^ ]*_XYZ' /dev/null $i ; done | awk -F: '{a[$1]=a[$1]";"$2;} END{for (x in a) print x ":" substr(a[x],2);}'

しかし、出力は次のように言います。

: No such file or directory
: No such file or directory
file.c.txt:FOUND1_XYZ;FOUND2_XYZ

したがって、何らかの方法でsearchFiles.txtで指定された最後のファイル名のみを検索できますが、他の初期ファイルは見つからないため、「該当するファイルまたはディレクトリはありません」というエラーが発生します。

私の予想結果は次のとおりです。

file.a.txt:FOUNDSTR_XYZ
file.b.txt:FOUNDSTR1_XYZ;FOUNDSTR2_XYZ;FOUNDSTR3_XYZ
file.c.txt:FOUND1_XYZ;FOUND2_XYZ

また、「find」コマンドの「-name」フラグが役に立つかどうかを調べようとしましたが、ここではsearchFiles.txtのファイルリストを正確に提供する方法を理解していません。次の試みが失敗しました。

find . -type f -name `cat searchFiles.txt` -exec grep -o '[^ ]*_XYZ' /dev/null {} \;

返品:

  • ディレクトリには最大数千のファイルを含めることができ、searchFiles.txtで検索されるファイル名は数百にすることができます。

  • ファイル名は何でも構いませんが、どのようなパターンにも従いません。

  • searchFiles.txt で提供されるファイル名は、file.a.txt の代わりに a.txt のような部分名であってもよい。ファイル名「file」の初期静的部分を意味する。 searchFiles.txt に存在する場合も存在しない場合もあります。

  • シェルスクリプトではなく、1行のコマンドを見つける方が良いでしょう。

これに助けが必要ですか?

ベストアンサー1

awkGNUを使用して、次のすべてのことを実行できる必要があります。

find . -type f -print0 |
  gawk '
    step == 1 {files[$0]; next} # record file names in "files" array
    step == 2 {
      # determine which files to look into (added to ARGV array for
      # processing in step 3)
      if ($NF in files) ARGV[ARGC++] = $0; next
    }
    NF {
      # record all matches (here in fields matched by FPAT)
      $1 = $1 # force a rebuild of $0 joining fields with OFS
      matches[FILENAME] = matches[FILENAME] \
                          (matches[FILENAME] == "" ? "" : OFS) \
                          $0
    }
    END {
      for (file in matches)
        print file ": " matches[file]
    }' step=1 searchFiles.txt \
       step=2 RS='\0' FS=/ - \
       step=3 RS='\n' FPAT='[^ ]*_XYZ' OFS=';'

上記では、ファイル名はに保存されますsearchFiles.txt。ファイルの行がサフィックスのリストである場合は、連想配列の代わりに正規表現を作成できます。

find . -type f -print0 |
  gawk '
    step == 1 {
      gsub(/[][^$*()+{}?\\.|]/, "\\\\&") # escape regexp operators
      regex = regex sep $0; sep = "|"
      next
    }
    step == 2 {
      # determine which files to look into (added to ARGV array for
      # processing in step 3)
      if ($NF ~ ("(" regex ")$")) ARGV[ARGC++] = $0; next
    }
    NF {
      # record all matches (here in fields matched by FPAT)
      $1 = $1 # force a rebuild of $0 joining fields with OFS
      matches[FILENAME] = matches[FILENAME] \
                          (matches[FILENAME] == "" ? "" : OFS) \
                          $0
    }
    END {
      for (file in matches)
        print file ": " matches[file]
    }' step=1 searchFiles.txt \
       step=2 RS='\0' FS=/ - \
       step=3 RS='\n' FPAT='[^ ]*_XYZ' OFS=';'

難読化が必要な場合は、1行に入力できます。

find . -type f -print0|gawk '!s{gsub(/[][^$*()+{}?\\.|]/,"\\\\&");r=r p $0;p="|";next};s==2{if($NF~("("r")$"))ARGV[ARGC++]=$0;next};NF{$1=$1;m[FILENAME]=m[FILENAME](m[FILENAME]==""?"":OFS)$0};END{for(f in m)print f":"m[f]}' searchFiles.txt s=2 RS=\\0 FS=/ - s=3 RS=\\n FPAT='[^ ]*_XYZ' OFS=\;

ファイル名と内容に含めることができる文字については想定しません。ただし、その文字はロケールで有効な文字でなければなりません。サフィックスには改行文字を使用できませんが、これはsearchFiles.txt

おすすめ記事