ファイル内の行の順序を変更する

ファイル内の行の順序を変更する

特定のパターンで行の順序を変更しようとしています。多数の行 (例: 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 し、next 行を取得し、hそれを old し、next 行を取得し、G保持されている行を et (パターン スペースに追加) し、p3 行目と 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ため、この問題は発生しません。-neprint

それでも、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 

関連情報