使用sed更改文件中一行的位置

时间:2017-01-28 17:52:59

标签: bash sed

我想知道如何更改文件中一行的位置(最好使用sed)。例如,考虑包含

的文件
goal identifier statement  
let statement 1  
let statement 2  
forall statement  
other statements

我希望能够做到这一点

goal identifier statement  
forall statement  
let statement 1  
let statement 2  
other statements  

我改变 forall 行的位置,然后将其带到目标行之后。 forall 目标是可用于识别行的正则表达式。

5 个答案:

答案 0 :(得分:5)

您可以尝试将line 4移至line 2,我想将line A移至line B,其中A>B

sed -n '2{h; :a; n; 4{p;x;bb}; H; ba}; :b; p' file

A<B

sed -n '2{h; d}; 4{p; x;}; p' file

你得到的,在第一种情况下:将line 4移至line 2

goal identifier statement
forall statement
let statement 1
let statement 2
other statements

你得到的,在第二种情况下:将line 2移至line 4

goal identifier statement  
let statement 2  
forall statement  
let statement 1  
other statements

<强>解释

sed -n '              #silent option ON
    2{                #if is line 2
        h             #Replace the contents of the hold space with the contents of the pattern space
        :a            #label "a"
        n             #fetch the next line
        4{            #if is line 4
            p         #print line 4
            x         #Exchange the contents of the hold and pattern spaces
            bb        #goto "b"
        }
        H             #appends line from the pattern space to the hold space, with a newline before it.
        ba            #goto "a"
    }
    :b                #Label "b"
    p                 #print
' file 

修改

如果您想使用regex来识别线条,可以修改第一个命令

sed -n '/goal/{p;n;h;:a;n;/forall/{p;x;bb};H;ba};:b;p' file

答案 1 :(得分:1)

$ cat r.awk
BEGIN {
    forall_re = "^forall" # examples of regexps
    goal_re   = "^goal"
}

function tag(l) { # tag a line
    if      (l ~ goal_re  ) return "goal"
    else if (l ~ forall_re) return "forall"
    else                    return "rest"
}

{ # store entire file in array; give a tag to every line
    lines[NR] = $0 
    tags[NR]  = tag($0)
}

function swap0(a, i, j,   tmp) {
    tmp = a[i]; a[i] = a[j]; a[j] = tmp
}

function swap(i, j) {
    swap0(lines, i, j); swap0(tags, i, j)
}

function rise(i) {
    # TODO: add error check
    while (i - 1 > 0 && tags[i - 1] != "goal") {
        swap(i, i - 1); i--
    }
}

function process(    i) {
    for (i = 1; i <= NR; i++)
        if (tags[i] == "forall") rise(i)
}

function dump(    i) { # print the array
    for (i = 1; i <= NR; i++)
        print lines[i]
}

END {
    process()
    dump()
}

输入文件的示例

$ cat r.txt
goal identifier statement  
let statement 1  
let statement 2  
forall statement A  
other statements

goal identifier statement  
let statement 1  
let statement 2  
forall statement B
other statements

用法:

$ awk -f r.awk r.txt
goal identifier statement  
forall statement A  
let statement 1  
let statement 2  
other statements

goal identifier statement  
forall statement B
let statement 1  
let statement 2  
other statements

答案 2 :(得分:1)

sed用于单个行上的简单替换,即全部。对于其他任何事情,你应该使用awk来获得软件的每个理想属性(清晰度,简单性,可移植性等等):

$ awk 'NR==FNR{if (/forall/) {f=FNR; v=$0} next} FNR!=f; /goal/{print v} ' file file
goal identifier statement
forall statement
let statement 1
let statement 2
other statements

答案 3 :(得分:0)

sed -r '/goal/{                 # if match "goal" line
    :X                          # this is a lable for branch command
    N                           # append next line
    /forall[^\n]*$/{            # if match "forall" line move to "goal" line below
        s#^([^\n]*)(.*)(\n[^\n]*)$#\1\3\2# 
        b                       # after move finished branch to end
    } 
    bX                          # branch to :X for appending next line
}' file
goal identifier statement  
forall statement  
let statement 1  
let statement 2  
other statements

答案 4 :(得分:0)

使用vim使用正则表达式$ REGEX_EXPRESSION在$ FILENAME中查找一行并将该行移至$ LINE_NUMBER的一种不太可怕的方式:

vim -c "g:$REGEX_EXPRESSION:m$LINE_NUMBER" -cwq "$FILENAME"

说明:-c是vim中的命令,因此它会转到与该正则表达式匹配的第一行,然后将其移至指定的行号,然后执行命令wq(或写入并放弃)。