私はこのパターンを持つ数百のファイルを持っています
@<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}'
ありがとうございました
お使いのバージョンの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)' *
どう?
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
に移動します。
タスクは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
nawk '/^@<TRIPOS>BOND/{getline;if( $0 ~ /^@/){print "mv", FILENAME, "../NewLoc/"}}' * | bash
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
それはそれほど単純ではありません:
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します。