私はubuntu端末を使用しています。ファイルの特定の行(11番目の位置)を最初の行に移動してから、最終結果を新しいファイルに転送する必要があります。元のファイルには数百行が含まれています。
これまでのところ、sedコマンドツールを使用しようとしましたが、希望どおりの結果が得られません。これは私がこれまでに得たものです:
[mission 09] $ sed -n -e '1p' -e '11p' bonjour > bonjour2
ただし、新しいファイルの1行目と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
なにか提案を ?
sed -n '1h;2,10H;11G;11,$p'
最初の行、新しい行のためにh
をコピーし、10までH
を追加します。
At 11行目、ホールドスペースを取得します
From 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行目には、ホールドから戻された「11G」(つまり1-10)が出力され、11行目に追加されます。
$までの12行目は、-n
。
2つ作ろう-e
あなたのような:
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が取得したものを一掃します。
paramsを持つ関数として
常に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
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 [〜#〜](編集者ではなく、エドから盗まれた!))
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 ;
これが最適な形式です。対称。
ed
を使用する(sed
およびgrep
の派生元である行エディター):
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
上記のバリエーションのいずれかの実行例:
$ 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
last行を常に先頭に移動するには、$m0
の代わりに11m0
を使用します。文字列French:
で始まる行を常に移動するには、/^French:/m0
を使用します。
私が正しく理解していれば、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
これは、ファイルを通過するtwoパスで実現できますが、最初のパスはショートカットにすることができるので、それほどひどくはありません。
( sed -n '11 {p;q}' file ; sed 11d file ) > newfile
基本的に、最初のsed
コマンドは、11行目のみを出力してから終了します。 2番目のsed
コマンドは、すべての行を出力しますexcept 11行目。
その結果、事実上、11行目が新しいファイルの前に移動されます。
以下の私の元の回答を投稿した後、配列を持つことはやりすぎであり、本当に必要なのは次のものだけであることに気づきました:
awk '
NR < 11 { buf = buf $0 ORS; next }
{
print
printf "%s", buf
buf = ""
}
' file > new_file
例えば。:
$ seq 15 | awk '
NR < 11 { buf = buf $0 ORS; next }
{
print
printf "%s", buf
buf = ""
}
'
11
1
2
3
4
5
6
7
8
9
10
12
13
14
15
バッファーにスカラー変数の代わりに配列を使用する元の答え:
awk '
NR < 11 { buf[++bufSz] = $0; next }
{
print
for (i=1; i<=bufSz; i++) {
print buf[i]
}
bufSz = 0
}
' file > new_file
例えば。:
$ seq 15 | awk '
NR < 11 { buf[++bufSz] = $0; next }
{
print
for (i=1; i<=bufSz; i++) {
print buf[i]
}
bufSz = 0
}
'
11
1
2
3
4
5
6
7
8
9
10
12
13
14
15
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
投稿されたものより単純なsed(POSIX、ラベルなし):
seq 20 | sed '1,10{H;1h;d;};11G'
つまり、1行目から10行目で、ホールドスペースをそれらの行で埋めます(印刷しません)。 11行目で、保留スペースを元に戻し、それ以降、sedにデフォルトを実行させます。各行を出力するだけです。 11行目以降のスクリプトは何もしないことに注意してください。デフォルトではsedのままにしてください。おそらくより高速です。
Awkで:
awk 'NR <11{ hold=hold RS $0 }
NR==11{ print $0, hold }
NR >11
' file
1つのライナーとして:
$ seq 15 | awk 'NR<11{hold=hold RS $0}NR==11{print $0,hold}NR>11'
11
1
2
3
4
5
6
7
8
9
10
12
13
14
15