如何使用sed在特定单词之后交换单词,这些单词可以排成一行,也可以排成不同行?

时间:2019-05-02 01:23:38

标签: shell sed scripting

我有一个以行开头的文件:

OCCUPY 12 EVERY PIC 32(12).     SUNNY 
OCCUPY 45 EVERY PIC X(21).      SUNNY

某些行可以分成两行:

1      OCCUPY 12 EVERY PIC 32(12).    SUNNY
2              OCCUPY 45 EVERY        SUNNY 
3                   PIC X(21).        SUNNY

所需的输出是:

PIC 32(12) OCCUPY 12 EVERY.    SUNNY
PIC X(21) OCCUPY 45 EVERY.     SUNNY 

因此,我需要将分隔的行合并为一行,并交换单词。 因此,对于一行中的那些,我正在使用命令:

sed 's/\(OCCUPY.*EVERY\) *\(PIC *[^ }*\)\./\2 \1./'
sed -Ez 's/(OCCUPY)\s+([0-9]+)\s+(EVERY)\s+(PIC)\s+([^)]+\))/\4 \5 \1 \2 \3/g'

这些命令有效,但仅当行在一行中并且将单词SUNNY和点移一个空格时才有效。 SUNNY一词必须在同一字段中。因此,错误的输出是:

PIC 32(12) OCCUPY 12 EVERY.     SUNNY
PIC X(21) OCCUPY 45 EVERY .   SUNNY 

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:1)

使用GNU sed作为-E的缩写,-z\s的缩写:

[[:space:]]

,如果每一行都适合该模式的空格/非空格字符串,则可以将其减少为:

$ sed -Ez 's/(OCCUPY\s+[0-9]+\s+EVERY)\s+(PIC\s+[^)]+\))/\2 \1/g' file
PIC 32(12) OCCUPY 12 EVERY.
PIC X(21) OCCUPY 45 EVERY.

或者该行是否可以在任何空格处分割,而不仅限于示例中显示的位置:

$ sed -Ez 's/((\S+\s+){2}\S+)\s+(\S+\s+\S+\))/\3 \1/g' file
PIC 32(12) OCCUPY 12 EVERY.
PIC X(21) OCCUPY 45 EVERY.

鉴于更新后的输入/输出,脚本仍然有效:

$ sed -Ez 's/(OCCUPY)\s+([0-9]+)\s+(EVERY)\s+(PIC)\s+([^)]+\))/\4 \5 \1 \2 \3/g' file
PIC 32(12) OCCUPY 12 EVERY.
PIC X(21) OCCUPY 45 EVERY.

$ sed -Ez 's/(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+\))/\4 \5 \1 \2 \3/g' file
PIC 32(12) OCCUPY 12 EVERY.
PIC X(21) OCCUPY 45 EVERY.

答案 1 :(得分:0)

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

sed -E '/OCCUPY/{:a;/ PIC/!{N;s/\n\s*//;ta};s/PIC/\n&/;s/(.*) \n([^.]*)/\2 \1/}' file

此操作着眼于包含OCCUPY的行,然后如果同一行中还不包含PIC,则将附加行(删除其换行符)附加到行。

使用引入的换行符作为分隔符,然后使用模式匹配将模式空间中的行重新排列为所需格式。