2つのテキストファイルがあり、あるファイルから別のファイルに複数行をコピーしたいと思います。ファイル1にはパッケージのリストがあり、それをリスト2にコピーしたいと思います。このパッケージのリストはファイル1の先頭にはありませんが、リストの先頭に%packagesタグがあり、最後に%endタグがあります。 %packagesと%endの間のすべての行をファイル1からファイル2にコピーする方法を知りたいです。
答え1
%packages と %end の間のすべての行を file1 から file2 にコピーするには:
awk '$1=="%end" {f=0;next} f{print;next} $1=="%packages" {f=1}' file1 >>file2
この回避策は、%packages行と%end行を削除することです。 (この行も移動するには、以下に簡単な解決策があります。)
awk
ファイルのすべての行に対して暗黙的に繰り返されるため、上記のコマンドが適用されます。file1
このコマンドは、呼び出されたフラグを使用してのf
パッケージセクション内にあることを確認しますfile1
。パッケージセクションの各行はstdoutとして印刷されますfile2
。
awk
次のコマンドを1つずつ見てみましょう。
$1=="%end" {f=0;next}
このコマンドは、行がで始まることを確認します
%end
。その場合、フラグは0に設定され、対応する行f
にジャンプします。next
f{print;next}
このコマンドはフラグが
f
ゼロでないことを確認します。 0以外の場合は、行を印刷して次の行にジャンプします。$1=="%packages" {f=1}
このコマンドは、行がで始まることを確認します
%packages
。もしそうなら、フラグをf
1に設定してそれ以降の行を印刷します。
マーカーラインが含まれています:
上記には %packages と %end バーは含まれません。これを含めるには、次のようにします。
awk '/^%packages/,/^%end/ {print}' file1 >>file2
答え2
awkに加えて考慮すべきもう一つの解決策はsedです。
sed -n '/%packages/,/%end/ w file2' file1
出現順に分類:
sed
明らかにそれ自体には開口部があります'
。これはsedに、この時点から最後まで'
すべてがsed自体の引数/コマンドであることを伝えます。それ以降の内容はすべて入力されます(またはリダイレクト>ファイルを使用している場合は出力)。
-n
印刷を抑制します。これがない場合、file1 の内容全体が印刷され、一致するテキストが 2 回印刷されます。
/pattern1/,/pattern2/
一致させる範囲の制限を定義します。
w file
ファイルに書き込みます。最後のパラメータでなければならず、その後にファイル名(または現在のディレクトリにない場合は/ path / to / file)が続きます。
最後に、シングルを閉じた後に'
入力ファイルがあります。
最後の2つのメモ:
1. 一部の人々は入力ファイルにリダイレクトを使用するのが好きなので、最終的なコマンドは次のようになります。
sed -n '/%packages/,/%end/ w file2' <file1
利点は、より明確であることです。つまり、入力をどこで受け取るかは明らかです。同様に、次w file
を使用する代わりに、出力を> fileにリダイレクトできます。
sed -n '/%packages/,/%end/ p' <file1 >file2
この場合、p
印刷一致を追加します(選択のために-nオーバーライド)。
ただし、sedは複数の入力ファイルで動作できます。
sed -n '/%packages/,/%end/ w file-final' file1 file2 file3
リダイレクトでは、ユーザーがこの機能を無視することがよくあります。
2. 上記の一致には、開始行と終了行が含まれます。 sed は単語レベルではなく行レベルで動作するためです。 1つの解決策は、単により多くのsedにパイプすることです。
sed -n '/%packages/,/%end/ w file2' file1 | sed -e '1d' -e '$d'
次の新機能が導入されました。
-e
同じ入力で複数のコマンドを実行できます。一致するパターンを削除して、
1
バー番号の一致が機能します
d
。最初のコマンドの行番号 1 は
$
入力ストリームの終わりです。 sed は単語レベルではなく行レベルで動作するため、最後の行全体が削除されます。
ただし、実際にはグループ化のために中かっこを使用して、単一のsed呼び出しでこれを行うことができます(明確にするためにスクリプトで)。
#!/bin/bash
sed -n '
/%packages/,/%end/ {
/%packages/n
/%end/ !{
w file2
}
}
' file1
ここで(グループ化に加えて)唯一の新しい点は、!
一致を否定することです。
/pattern/n
パターンで印刷された線を抑制します(-n
最初と同じ)。
/pattern/ !
パターンと一致しないすべての項目を選択します(逆一致)。しかし、その理由は簡単です。 %end パターンを抑制するために別のアクションをとると、/%end/n
範囲を制限するためにこれを抑制し、ファイルは最後まで印刷されます。
答え3
最も理解しやすい:
grep -A 1000 '%packages' xx | grep -B 1000 '%end'
最初の部分は%packages
1000行(一致する行を含む)を検索して印刷します。ㅏ その後。
パイプの後ろの2番目の部分:%end
1000行(一致する行を含む)をすべて検索して印刷します。第二 前に。
ファイルが1000行を超える場合は、1000を大きい数に変更してください。
欲しいならただ開始および終了正規表現を含む検索パターンのみを含む行を一致させます。金利。
grep -A 1000 '^%packages$' xx | grep -B 1000 '^%end$'
一致する行を含めない場合は、別のパイプを追加してください。
grep -A 1000 '^%packages$' xx | grep -B 1000 '^%end$' | grep -v -e '^%packages$' -e '^%end$'
ここでは-e
、複数の検索パターンを指定し、-v
一致の意味を変更して、一致しない行を選択するために使用できます。