将特定行从一个位置移动到另一个位置

将特定行从一个位置移动到另一个位置

我使用的是 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

上述变体之一的运行示例:

$ 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,这是一个范围行号和“保持”(存储)命令。还没有打印任何内容。

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 -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 行然后退出。第二个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

相关内容