特定の行をある場所から別の場所に移動

特定の行をある場所から別の場所に移動

Ubuntu端末を使用していますが、ファイルの特定の行(11番目の場所)を最初の行に移動してから、最終結果を新しいファイルに転送する必要があります。元のファイルには数百行が含まれています。
これまでsedコマンドツールを試してみましたが、目的の効果が得られませんでした。これが私が今まで得たものです:

[mission 09] $ sed -n -e '1p' -e '11p' bonjour > bonjour2

ただし、新しいファイルでは最初の行と11行目のみが表示されます。しかし、新しいファイルが残りの元の行と一緒に希望のリビジョン位置を持つことを望みます。

入力する:

English: Hello 
Turkish: Marhaba 
Italian: Ciao 
German: Hallo 
Spanish: Hola 
Latin: Salve 
Greek: chai-ray 
Welsh: Helo 
Finnish: Hei 
Breton: Demat 
French: Bonjour 

希望の出力

French: Bonjour 
English: Hello 
Turkish: Marhaba 
Italian: Ciao 
German: Hallo 
Spanish: Hola 
Latin: Salve 
Greek: chai-ray 
Welsh: Helo 
Finnish: Hei 
Breton: Demat 

どんな提案がありますか?

答え1

使用(およびed派生行エディタ):sedgrep

printf '%s\n' '11m0' 'w bonjour2' 'q' | ed -s bonjour

11m0これにより、ファイルに編集コマンドが適用され、最初の行の前に11行目が移動します。その後、生成された文書がファイルに書き込まれ、bonjour2終了します。

または:

printf '%s\n' '11m0' ',p' 'Q' | ed -s bonjour >bonjour2

...コマンドを使用して特定のファイルに書き込むのではなく、ファイルed全体を標準出力として印刷します。その後、結果は新しいファイル名にリダイレクトされます。この,pコマンド(略称1,$p)は、文書全体を標準出力に出力してQ強制終了します(文書が変更された場合でも)。

文書を所定の場所に変更するには(元のファイルの変更など)、結果をファイル自体に書き換えます。

printf '%s\n' '11m0' 'wq' | ed -s bonjour

上記の変形の1つの実行例:

$ printf '%s\n' '11m0' ',p' 'Q' | ed -s bonjour >bonjour2
$ cat bonjour2
French: Bonjour
English: Hello
Turkish: Marhaba
Italian: Ciao
German: Hallo
Spanish: Hola
Latin: Salve
Greek: chai-ray
Welsh: Helo
Finnish: Hei
Breton: Demat

いつも動いて最後行を一番上に移動するには、代わりに$m0を使用してください11m0。常に文字列で始まる行を移動するには、をFrench:使用します/^French:/m0

答え2

sed -n '1h;2,10H;11G;11,$p' 

最初の行はh改行のためにコピーされてHから10に追加されます。

存在する11行目、予約済みスペースの確保

~から11終了して印刷します。


]#  sed -n '1h;2,10H;11G;11,$p' bonj 
French: Bonjour 
English: Hello 
Turkish: Marhaba 
Italian: Ciao 
German: Hallo 
Spanish: Hola 
Latin: Salve 
Greek: chai-ray 
Welsh: Helo 
Finnish: Hei 
Breton: Demat 

これは良いです:

]# seq 20 | sed -n '1h;2,10H;11G;11,$p' 
11
1
2
3
4
5
6
7
8
9
10
12
13
14
15
16
17
18
19
20

例を挙げてみましょう。

]# sed -e 1p -e 11p -n bonj 
English: Hello 
French: Bonjour 

...-n最後のスイッチは両方の式で動作することを示すためのものです。

私も-n、それなら1h;2,10Hこれは、これは1,10H、これは範囲行番号と「hold」(保存)コマンド。まだ何も印刷されていません。

11,$pもう一つの範囲です。 11行目では、予約ステータス(例:1-10)で返したばかりの内容「11G」を印刷して11行目に追加します。

$までの12行目は-n


私は-eあなたのように2つのことをする必要があります:

sed -n -e '1h;2,10H' -e '11G;11,$p'

1,10から保留し、11,$から印刷します。


11行目が最初にありG、次にpこれが重要です。

]# seq 20 | sed -n -e '1h;2,10H' -e '11,$p;11G'
11
12
13
14
15
16
17
18
19
20

ここで、12行目は11行目に印刷された内容を消去します。


パラメータを持つ関数として

11行目は常に "putfirst"関数のために退屈です:

]# declare -f putfirst 
putfirst () 
{ 
    e="1h;2,$(($1-1))H;${1}G;${1},\$p";
    sed -ne "$e" $2
}

2つのステップ:文字列を生成し、次にsedを呼び出します。 「$」には2つの意味があります。 「p」は変数ではありません!

有効な最低数字は次のとおりです。

]# seq 7 | putfirst 3 
3
1
2
4
5
6
7

または、オリジナルの「bonj」ファイルを使用してください。

]# putfirst 4 bonj | putfirst 6 |head -4
Latin: Salve 
German: Hallo 
English: Hello 
Turkish: Marhaba 

これは2つの連続したsedですが、2つの作業が完了しました。


真珠

perl -ne '$n++; $h.=$_ if $n<11; print $_.$h if $n==11; print if $n>11' <(seq 20)

一部のスクリプトと同様に、ファイル名が必要で、オプションは必要ありません。

$want=11 ;
while (<>) {
    $n++ ;
    if ($n < $want)            # before $want: store line
        { $lowlines .= $_ ; 
          next }               # next line (avoids 'else')  
    if ($n == $want)           # at line $want: append stored lines to $_    
        { $_ .= $lowlines }   
    print ;                    # print $_ for $n not less than $want
}

AWK(Edから盗んだのです(編集者ではありません!))

NR < 11 { 
    buf[NR] = $0; next 
}
NR >=11 {
    print
    if (NR == 11) {
        for (i=1; i<11; i++) { print buf[i] }
    }
}

NRは増加の代わりに使用してnプロセスをより明確にします。同じ「トリック」:nextダウンストリームを単純化します。


そしてperl -n

$n++ ;
$tmp = $tmp . $_  if $n < 11  ; 
print  $_ . $tmp  if $n == 11 ;
print  $_         if $n > 11  ;

これが最良の形式です。対称。

答え3

私が正しく理解したら、11行目だけを最初の行に移動したいと思います。

したがって、原本が次のような場合

Original line 1
Original line 2
...
Original line 18
Original line 19
Original line 20

それから結果は

Original line 11
Original line 1
Original line 2
...
Original line 9
Original line 10
Original line 12
Original line 13
...
Original line 19
Original line 20

これは次のことで達成できます。二つファイルを繰り返しますが、最初のパスは短くなる可能性があるため、あまりにも恐ろしいことはありません。

( sed -n '11 {p;q}' file ; sed 11d file ) > newfile

デフォルトでは、最初のsedコマンドは行11を印刷してから終了します。 2番目sedのコマンドは各行を印刷します。とは別に11号線。

その結果、行11は実際には新しいファイルの前に移動します。

答え4

そしてPOSIX sed

$ sed -e '1,11!b' -e '11!H;1h;11!d;G' file

使用perl:

$ perl -lne '
   push(@A,$_),next if $. < 11;
   print for $_, splice @A;
' file

使用bash:

$ (head -n 11 - | tee log | tail -n 1 -; head -n 10 log; cat -;) < file

関連情報