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


11

特定のパターンで行の順序を変更しようとしています。多くの行(例: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.
...

回答:


12

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である行に入力を保存します。つまり、入力がゼロのときに印刷した直後です。


ここに小さな欠陥があります。私の回答、マイナーな改善の部分を参照してください
セルギーコロディアズニー

良いキャッチをありがとう。私はの形式で私の回答に修正を組み込んだNR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }
DopeGhoti 2017年

23
$ seq 9 | sed -n 'p;n;h;n;G;p'
1
3
2
4
6
5
7
9
8

すなわち、p取得し、現在の行をRINT n、EXTのいずれかをh取得し、それ古いnEXTのいずれかを、G他ハンドヘルドライン(パターンスペースに追加し)およびpRINTスワップ第三及び第2の配線と2ラインパターンスペースこと。


3

別のawkアプローチ:

awk '{print $0; if ((getline L2)>0 && (getline L3)>0){ print L3 ORS L2 }}' file

出力:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

  • (getline L2)>0 && (getline L3)>0-次の2つのレコードが存在する場合、それらを抽出します

  • 2番目と3番目の各レコードはそれぞれL2L3変数に割り当てられます


1
これらの変数はL(小文字)で始まると想定しています。それらは12と13の数字のように見えるため、読みやすさの選択肢としては不十分です。より良い選択はline2、などである可能性があります
追って通知があるまで一時停止します。

@DennisWilliamson、大文字に変更
RomanPerekhrest

1

使用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)を取得して、要求された順序で出力します:line1、line3、line2。


1

1つの方法は次のとおりです。

sed -e '
   /\n/s/\(.*\)\(\n\)\(.*\)/\3\2\1/;//b
   $!N;$q;N;                            # load up the pattern space with 3 lines provided eof not reached
   P;D;                                 # first just print the first line then interchange the two and print them
' yourfile

または、

perl -ne 'print $_, reverse scalar <>, scalar <>' yourfile

結果

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

1

なぜwhileループを作成しないのですか?展開された形式:

( while read a
  do
    read b
    read c
    echo "$a"
    echo "$c"
    echo "$b"
  done
) < input.txt

「単一行形式」の場合:

( while read a ; do read b ; read c ; echo "$a" ; echo "$c" ; echo "$b" ; done) < input.txt

出力:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

1

Perl

perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt

ここでの考え方は、%行番号$.変数を使用してモジュロ演算子を使用し、1つおき、1つおき、および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の場合、ファイルの最終行が$に対して1の出力を生成する場合。%3、前のコードは、理由の無条件の印刷の空白改行を出力する問題を持ってEND{print delay}いるので、printコメントに記載された機能は、常にそれが動作しているものは何でも変数に改行を追加します。perlバージョンの場合、-neフラグprint機能では改行が追加されないため、この問題は発生しません。

それにもかかわらず、コメントでDope Ghotiが言及したように、awkの場合の修正は一時的な変数の長さを確認することです。同じ修正の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 

1
この修正には、「間違った」行数のファイルの出力に空白行が追加されるという潜在的なマイナーな欠陥があります。私は(for awk)での私の答えの改善を組み込むことでこれを修正しましたNR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }
DopeGhoti 2017年

1
@DopeGhoti perlの-neフラグ付き印刷では改行が出力されないため、この問題はperlでは発生しません。実際に出力しますが、ヌル文字列であり、後続の改行はありません。それにもかかわらず、問題への言及と同じ修正を私の回答に追加しました。ありがとう!
Sergiy Kolodyazhnyy 2017年

1

Vim

長いファイルには適していませんが、ファイルを編集しているだけで、たとえばyamlスタンザの順序を変更したい場合に便利です。

最初にマクロを記録します。

gg qq j ddp j q

そして、必要な回数繰り返します:

@q @q @q ...

またはちょうど例えば

3@q

説明:

  • gg-最初の行に移動
  • qq-マクロの記録を開始する
  • j-2行目に移動
  • ddp-2行目と3行目を入れ替えます
  • j-4行目に移動します。つまり、次の3行の最初の行に移動します
  • q-記録を停止
  • @q-マクロを1回再生する
  • 3 @ q-マクロを3回再生します

1
手動で繰り返すの@q @q @qではなく、この方法で行うことができます-3 3@q回繰り返します。100@q-マクロを100回繰り返します。
MiniMax

0

使用法: ./shuffle_lines.awk input.txt

場所はシステムによって異なる場合がある#!/usr/bin/awk -fため、シバンを確認awkしてください。

#!/usr/bin/awk -f

{
    if ((NR + 1) % 3 == 0) {
        buffer = $0;
    } else if (NR % 3 == 0) {
        print $0 ORS buffer;
        buffer = "";
    } else {
        print;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.