
特定のパターンで行の順序を変更しようとしています。多数の行 (例: 99 行) を含むファイルを操作しています。3 行ごとに、2 行目を 3 行目に、3 行目を 2 行目にしたいと思います。
例。
1- 入力:
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
...
2- 出力:
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
...
答え1
$ seq 9 | sed -n 'p;n;h;n;G;p'
1
3
2
4
6
5
7
9
8
つまり、p
現在の行を rint し、n
ext 行を取得し、h
それを old し、n
ext 行を取得し、G
保持されている行を et (パターン スペースに追加) し、p
3 行目と 2 行目を入れ替えた 2 行のパターン スペースを rint します。
答え2
awk
整数計算の使用:
awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay } }' /path/to/input
モジュラス演算子は整数除算を実行し、剰余を返します。したがって、各行では、1、2、0、1、2、0 [...] というシーケンスが返されます。これを理解して、モジュラスが 2 である行の入力を後で使用するために保存します。つまり、入力が 0 のときにそれを印刷した直後に保存します。
答え3
使用perl
と短いスクリプト:
user@pc:~$ cat input.txt
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
user@pc:~$ perl -ne '$l2=<>; $l3=<>; print $_,$l3,$l2;' input.txt
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
スクリプトはファイル全体を処理し、各行 ( に格納$_
) に対して次の 2 行 ($l2
および$l3
) を取得し、要求された順序 (行 1、行 3、行 2) でそれらを出力します。
答え4
パール
perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt
ここでの考え方は、%
行番号$.
変数を持つモジュロ演算子を使用して、どの行が 1 行目、どの行が 2 行目、どの行が 3 行目であるかを判断することです。3 行目ごとに余りは 0 ですが、1 行目と 2 行目ごとに対応する番号が設定されます。
テスト:
$ cat input.txt
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
$ perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
マイナーな改善
2 行目を変数に格納する方法には欠陥があります。最後の行が「2 行目」の場合、つまりその行番号の余りが 2 の場合はどうなるでしょうか。私と DopeGhoti の回答の元のコードは、My dog is orange
最後の行を省略すると印刷されません。どちらの場合も、END{}
コード ブロックを使用して、印刷後に一時変数を設定解除すると、この問題が解決します。言い換えると、次のようになります。
$ awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay;delay=""}END{print delay}' input.txt
そして
$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s}' input.txt
この方法では、コードは 3 で割り切れる行数だけでなく、ファイル内の任意の行数に対して機能します。
コメントで言及された問題に対する追加の修正
awk の場合、ファイルの最後の行が $. % 3 に対して 1 の出力を生成する場合、前のコードでは、コメントで言及されている関数END{print delay}
が、print
操作対象の変数に常に改行を追加するため、 の無条件印刷が原因で空の改行が出力されるという問題が発生します。バージョンの場合、フラグ付き関数は改行を追加しないperl
ため、この問題は発生しません。-ne
print
それでも、awk の場合の修正は条件付きにすることです。コメントで Dope Ghoti が言及しているように、一時変数の長さを検証することです。同じ修正の Perl バージョンは次のようになります。
$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s if length $s}' input.txt