结合使用bash在文件中切换行顺序的sed命令

时间:2019-05-15 21:23:04

标签: bash sed

我有重复的sed命令,它们会切换第1行,第2行,第3行和第4行,等等。但是,当我尝试将它们合并时,它会添加重复的行并消除一些行。

编辑:

sed之前的原始文件如下:

Some code....
Some code...
Line-a
Line-b
Line-c
Line-d
Line-e
Line-f
some more...
some more...

提供所需输出的代码是:

sed -i '2{h;d};3{p;x}' file.txt && sed -i '4{h;d};5{p;x}' file.txt && sed -i '6{h;d};7{p;x}' file.txt 

我想使用的代码是:

sed -i '2{h;d};3{p;x};4{h;d};5{p;x};6{h;d};7{p;x}' file.txt

从订购的文件中获得所需的输出

Some code...
Some code...
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e
some more...
some more...

4 个答案:

答案 0 :(得分:4)

除非您使用的是GNU sed,否则( $!)除非当前行是文件的最后一行,否则( x )交换模式空间的内容并保持空格( n )将新行读入模式空间,( G )通过换行符将保留空间的内容追加到模式空间。 ( p )打印图案空间的内容。

$ cat file
one
two
three
four
five
six
seven
$
$ sed -n -i '$!{x;n;G};p' file
$
$ cat file
two
one
four
three
six
five
seven

要使其与POSIX具有100%的兼容性,您需要放弃就地编辑并将脚本分成多个命令:

sed -n -e '$!{x;n;G;}' -e 'p' file

这回答了the first version of OP's question。由于他们的最新编辑变得难以理解,因此我拒绝编辑。

答案 1 :(得分:4)

这对于sed是完全不合适的任务。只需使用awk,例如使用GNU awk进行“就地”编辑,因为出于某种原因,这似乎是一个优先事项,并且使用了经过修改的示例输入文件,因此可以清楚地知道哪些行和哪些行不会被交换:

$ cat file
with a some code here
and a some code there
Line-a
Line-b
Line-c
Line-d
Line-e
Line-f
here a code, there a code
everywhere a code, code

$ awk -i inplace 'NR>=3 && NR<=8{if ((++c)%2) p=$0; else print $0 ORS p; next} 1' file

$ cat file
with a some code here
and a some code there
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e
here a code, there a code
everywhere a code, code

除了仅使用GNU的-i inplace语法糖而不是> tmp && mv tmp file之外,该脚本将在任何UNIX机器上的任何shell中使用任何awk进行工作。


原始回复和下面的其他示例:

$ awk 'NR%2{p=$0;next} {print $0 ORS p}' file
Some code...
Some code...
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e

以上内容可在任何UNIX盒中的任何shell中使用任何awk进行工作。

只想在第4行和第7行之间交换吗?这是微不足道的调整,因为这是完成任务的正确工具

$ seq 10 | awk 'NR<=3 || NR>=8{print; next} (++c)%2{p=$0;next} {print $0 ORS p}'
1
2
3
5
4
7
6
8
9
10

或者,如果您愿意:

$ seq 10 | awk 'NR>=4 && NR<=7{if ((++c)%2) p=$0; else print $0 ORS p; next} 1'
1
2
3
5
4
7
6
8
9
10

是否想每3行反转一次?同样,这很简单,因为这是完成任务的正确工具

$ seq 9 | awk 'NR%3{p2=p1;p1=$0;next} {print $0 ORS p1 ORS p2}'
3
2
1
6
5
4
9
8
7

希望您能得到图片...

答案 2 :(得分:2)

这可能对您有用(GNU sed):

sed '3,8{N;s/\(.*\)\n\(.*\)/\2\n\1/}' file

对于一系列行,请追加以下行,并使用模式匹配将它们交换。

如果要交换,请说第3-4行和第7-8行:

sed '3ba;7ba;b;:a;N;s/\(.*\)\n\(.*\)/\2\n\1/' file

或交换3-5和6-8行,使用:

sed '3,8{N;N;s/\(.*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/} file

答案 3 :(得分:1)

对于这个问题,有一个可以说更简单的GNU sed解决方案 1

1,2b   # In the range 1,2 ...
9,$b   # ... and also in 9,$, auto print and end this cycle.
3~2 {  # From line 3 and every second line thereafter,
  h    # hold, then
  d    # delete, and end this cycle.
}
G      # On every other line, append hold space and auto print.

测试:

# test.sh

cat > FILE <<EOF
Some code....
Some code...
Line-a
Line-b
Line-c
Line-d
Line-e
Line-f
Some more code...
Some more code...
EOF

sed '1,2b; 9,$b; 3~2{h;d}; G' FILE

输出:

Some code....
Some code...
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e
Some more code...
Some more code...

请注意,通过first~step选择行,例如3~2是GNU扩展。

这是基于Chap中交换行的一般示例。 O'Reilly sed和awk第二版的6。


1 但我同意Ed Morton的评论,即AWK更适合解决此问题。