我使用的是 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
的行编辑器):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
。
答案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