Bash

將特定行從一個位置移動到另一個位置

  • March 1, 2020

我正在使用 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 

有什麼建議嗎?

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,這是一個行號範圍和一個“保持”(儲存)命令。什麼都沒有列印出來。

11,$p是另一個範圍。在第 11 行,它列印了剛剛從保持中返回的“11G”(即 1-10)並附加到第 11 行。

第 12 行直到 $ 只是列印自己,因為-n.


我應該-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 行在列印後得到的內容。


作為帶有參數的函式

總是第 11 行對函式“putfirst”很無聊:

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

兩個步驟:字元串生成,然後是 sed 呼叫。“$”有兩種含義:“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 

這是連續兩個sed,但是現在做兩個操作。


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(從 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  ;

這是最好的格式。對稱的。

使用(和派生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

要始終將最後一行移到頂部,請使用$m0. 11m0要始終移動以字元串開頭的行French:,請使用/^French:/m0.

引用自:https://unix.stackexchange.com/questions/569148