web-dev-qa-db-ja.com

awkを使用して特定の2行パターンのファイルを検索する

私はこのパターンを持つ数百のファイルを持っています

@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
 1  3  5  ar
@<TRIPOS>SUBSTRUCTURE

それらのうち、一部のファイルは@<TRIPOS>BONDの後の行が欠落しており、次のようになります

@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE

@<TRIPOS>BONDの後に数値行がない作業ディレクトリ内のすべてのファイルを見つけて、別のディレクトリに移動しようとしています。これは簡単な作業であることは知っていますが、私はLinuxを初めて使用します。

注:ファイルの長さと行番号が異なるため、@<TRIPOS>BOND文字列の後の行を「削除」しています。

ここに私のコードの1つを示します。これはforループで書くことを計画していました。それは仕事をしませんが、私は私の試用版の1つを示すためにそれを示しています。

cat file | grep -A1 '@<TRIPOS>BOND' | awk 'FNR == 2 {print}'

ありがとうございました

3
Error404

お使いのバージョンのgrepがPCREモード(-P)をサポートしている場合、@<TRIPOS>BONDが後に続く(改行のみの)@<TRIPOS>SUBSTRUCTUREのインスタンスを見つける複数行一致を試すことができます。

grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *

\Q\Eは、この場合は不要かもしれませんが、リテラルマッチングを強制することを目的としています(@><が特別な意味を持つ場合Perl正規表現構文)。 -lは、一致を出力するのではなく、一致するファイルをリストするようにgrepに指示します。その後、ファイルのリストをmvコマンドへの入力として使用できます。

grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' * | xargs mv -t /path/to/newdir/


追加情報

マッチの2番目の部分をlookaheadとして表現することもできますが、この場合は利点はないと思います

grep -lzP '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *

pcregrep(標準のUbuntuシステムの一部ではありませんが、リポジトリから取得可能)の同等の式は次のようになります

pcregrep -lM '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *

そして

pcregrep -lM '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *
6
steeldriver

どう?

for file in *.txt; do 
    grep -A1 "@<TRIPOS>BOND" "$file" | grep -q SUBSTR && mv "$file" bad_files/
done

説明:

これは、現在のディレクトリ内のすべての.txtファイルをループし(ファイルに一致するものにblobに変更)、それぞれを$fileとして保存します。次に、$file@<TRIPOS>BONDを検索し、その行と次の行を出力します。これは、次のgrepを介して渡され、サイレント(-q)でSUBSTRが検索されます。見つかった場合、BONDの後の行はSUBSTRUCTUREです。必要な数値行ではなく、現在のファイルをフォルダーbad_filesに移動します。

3
terdon

タスクはawkを使用して非常に簡単です。これが私の例です。 file-nm(欠落していない場合)およびfile-m(欠落している場合)、および移動するファイル用のmovedディレクトリの2つのファイルを作成しました。

awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m

ここで@<TRIPOS>BOND文字列を見つけて、次の行に進み、その行が@<TRIPOS>SUBSTRUCTUREかどうかを確認します。存在する場合は、見つかったファイルのFILENAMEである「mv」を使用してシステムコールを行い、宛先として「移動した」。結果は次のとおりです。

$ ls
file-m  file-nm  moved


$ awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m      


$ ls                                                                                                                     
file-nm  moved


$ ls moved                                                                                                               
file-m
0
nawk '/^@<TRIPOS>BOND/{getline;if( $0 ~ /^@/){print "mv", FILENAME, "../NewLoc/"}}' * | bash
0
Richard Romanus

awkまたはgawkを使用する

awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")} exit}' <file_name>

説明

  • /@<TRIPOS>BOND/,/@/

    @<TRIPOS>BOND@で始まる次の行の間のブロックのみが必要です

  • getline

    @<TRIPOS>BONDの後の次の行を読む

  • if ($_ ~ /^@/)

    行が@で始まるかどうかを確認します

    • true

      メッセージを印刷する

      printf "%s:%s\n",$_,FILENAME
      

      ファイルを移動する

      system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")
      
    • false

      スクリプトを残す

      exit
      

$ cat foo
@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE

$ cat bar
@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
 1  3  5  ar
@<TRIPOS>SUBSTRUCTURE

$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' foo
@<TRIPOS>SUBSTRUCTURE:foo

$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' bar

$ cat foo_moved 
@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE

$ cat bar_moved
cat: bar_moved: No such file or directory
0
A.B.

それはそれほど単純ではありません:

find -type f -exec \
 awk '/@<TRIPOS>BOND/{getline; \
  if ($0 !~ /1  3  5  ar/){\
  printf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \
| bash

説明:

  • find -type f:現在の作業ディレクトリ内のすべてのファイルを検索します
  • awk '/@<TRIPOS>BOND/{getline; \:ファイル内の行を見つけて、次の行に移動します
  • if ($0 !~ /1 3 5 ar/){\:次の行が(!~)ではない場合、目的の「数値行」
  • printf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \:mvコマンドをビルドしてパイプする...
  • | bash:... bashして実行します。

そのため、コマンドは、/path/to/move/というディレクトリに数値行を含まないすべてのファイルをmvします。

0
chaos