sed スクリプトの使用:
#!/bin/sed -nf
: loop
H
s/\([^_]*_[^_]*\)_.*/\1/g
t clear_flag
: clear_flag
$! {
N
s/^\([^_]*_[^\n]*\)\n\(\1[^\n]*\)$/\2/
t loop
}
x
s/^\n//
s/\([^_]*_[^_]*\)_/\1=\1_/
s/\n/ /gp
s/.*//
x
D
私はすべてを説明しようとします。まず、同じプレフィックスで始まるすべてのファイルを結合するループがあります。あなたの例に基づいてプレフィックスを定義しました。これは、2 番目のアンダースコアで終わる文字列として定義されています。ループは、":" コマンドを使用してラベルで定義されます。ここでは、ループに「ループ」というラベルを付けました。さらに下では、必要に応じて、「t」test コマンドを使用してループの先頭に「ジャンプ」します。
最初のコマンドは、ホールド スペース (補助バッファー) に行を追加することです。行には、追加される前に sed によって自動的に改行 ('\n') がプレフィックスとして付けられます。
2 番目のコマンドは、プレフィックスを抽出します。これは、アンダースコア ( ) ではない一連の文字をキャプチャし[^_]*
、次にアンダースコア、さらにアンダースコア以外の文字をキャプチャすることによって行います。このパターンはバックスラッシュ括弧 (\(
と\)
) の間にあるため、sed はこのパターンに一致する入力をキャプチャし、名前付きの補助変数に保存します\1
(その行の最初のキャプチャであるため)。次に、アンダースコアとそれに続く一連の文字をスキップします。置換はキャプチャしたものなので、実際には 2 番目のアンダースコア以降をすべて削除しました。
回避策を使用して、最後の "t" コマンド以降またはスクリプトの開始以降に置換が成功したかどうかを示す seds 内部フラグをクリアします。テスト コマンド ("t") は、置換コマンドが成功した場合にラベルに分岐 (ジャンプ) し、内部フラグをクリアします。これは、さらに下にある 2 番目の「t」コマンドで必要です。成功または失敗した場合 (つまり、分岐するかどうか)、「clear_flag」ラベルの後も実行を継続します。
ここで、"{" コマンドを使用してコマンドのグループを開始します。ただし、その前にアドレスプレフィックスがあり、sed はこれらのコマンドを実行する必要があるかどうかを判断するために使用します。この場合、最後に読み取られた入力行が最後の行ではない場合にのみ、グループが実行されます (ドル記号 "$" は最後の入力行を表し、"!" は否定を表します)。
グループの最初のコマンドは、入力の次の行を現在のパターン スペース (つまり、作業バッファー) に追加します。前の行と新しい行は、改行文字 ( ) で区切られます\n
。
3 番目のコマンドは、新しく読み取った行がプレフィックスで始まるかどうかを確認し、分離されたプレフィックス (つまり、前の行) を削除します。前の行に保持したプレフィックスから 2 番目のアンダースコアを削除し、新しい行を追加したため、分離されたプレフィックスは改行文字の前で終了します。したがって、キャプチャされたパターンは[^\n]*
、アンダースコアの後の改行 ( ) ではない文字を読み取るようになりました。分離されたプレフィックスをキャプチャした後、前の行と新しい行を区切る改行文字をスキップしてから、別のキャプチャを開始します (これは次の場所に格納されます)。\2
、この行の 2 番目のキャプチャであるため)。このキャプチャは (うまくいけば) 2 行目に一致します。うまくいけば、最初のキャプチャで一致したものとまったく同じように一致を開始する必要があるためです (つまり、2 番目のキャプチャで最初に行うのは、最初のキャチャへの後方参照、つまり です\1
)。その後、改行ではない一連の文字を照合し、2 回目のキャプチャの後、行の終わりを期待します。
この最後の置換コマンドが成功した場合、新しく読み取られた行にも同じプレフィックスがあることがわかったので、ループの先頭に戻る必要があります。それが「t」コマンドの機能です。最後の「t」コマンド以降に置換コマンドが成功したかどうかをテストし、成功した場合は、指定されたラベルに分岐します。この場合、「ループ」ラベルに分岐 (ジャンプ) します。これで、以前の "t" 回避策が必要だった理由がわかります。それがなければ、最初の代替コマンドは成功するかもしれませんが、実際に関心のあるコマンドは失敗する可能性があり、「t」は依然として「ループ」ラベルに分岐します。
ループを抜ける場合は、新しく読み取られた行に同じプレフィックスがないことを意味します。したがって、以前に一致したものを印刷できるようになりました。
交換 ("x") コマンドを使用して、パターン スペースの内容をホールド スペースの内容と交換することから始めます。ここで、パターン スペースには同じプレフィックスを持つすべてのファイルが含まれ、ホールド スペースには現在のプレフィックスが分離された行に含まれ、次に同じプレフィックスを共有しない最初のファイルの行が含まれます。
以前にすべてのファイル名をホールド スペースに追加したため、すべてのファイル名が改行で区切られ、最初のファイル名も追加されたため、現在のパターン スペースの最初のバイトは改行文字になります。それを削除するには、単純に何も置き換えません。
次に、割り当ての形式を生成する必要があります。そのため、おなじみの代替コマンドがあります。ここでもプレフィックスを抽出しています.*
が、行の残りの部分をそのまま維持するために を削除しました。置換には、プレフィックス (キャプチャされた)、等号が含まれます。また、パターン スペースの最初のファイルから削除したもの (プレフィックスとアンダースコア) を復元します。
行を印刷する準備がほぼ整いましたが、ファイル名はまだ改行文字で区切られています。したがって、すべての改行g
をスペースで置き換えます (フラグは、入力行で置換コマンドを可能な限り繰り返すように sed に指示します)。行の準備ができたので、p
接頭辞を追加して、sedに印刷するように指示できます。
最後の手順は、次のプレフィックスのために、スクリプトを再度開始する準備をすることです。ホールド スペースは、新しいプレフィックスを持つファイル名を保存するために使用できるように、空にする必要があります。これで、パターン スペース内のすべての文字を何も置換しないコマンドがあり、その後に交換コマンドが続きます。
ホールドスペースが用意されています。次に、パターン スペースを準備する必要があります。新しい接頭辞を持つファイル名の最初の行のみを含める必要があります。その状態にするには、最初の行に格納されている古いプレフィックスを削除するだけです。s/.*\n//
最後の行 (ファイル名と新しいプレフィックスを含む) の文字を除くすべての文字を置き換えるようなこともできますが、D
コマンドはそれを行い、別の行を読み取らずにスクリプトの実行を強制的に再開するため、タイピングの手間が省けます。
スクリプトは少し不可解で、説明が圧倒されるかもしれませんが、何が起こるかを理解すると、簡単になります(r) =)
言及しなければならないこと: 入力をソートする必要があります (または、少なくとも同じプレフィックスを持つファイルをグループ化する必要があります)。
お役に立てれば!