【问题标题】:sort rows starting with pattern using awk or sed使用 awk 或 sed 对以模式开头的行进行排序
【发布时间】:2016-02-28 02:27:20
【问题描述】:

我想打印路由器配置并仅对以模式crypto isakmp key 6 开头的行进行排序。

重要的是我想把这些行放在同一个地方,所以这些行之前和之后的所有行都应该保持在同一个地方和顺序(不排序)。

示例输入文件:

123 345
678 901
bla bla bla
ble ble ble
crypto isakmp key 6 kokofeofepokpfowkfpwjeiofjwiojefiow address 123.456.789.012
crypto isakmp key 6 ofjwiojefiow352okdwofkwkfi9i42kpfsej09f09j4 address 123.456.789.012
crypto isakmp key 6 9i42kpfsej09f09j4ofjwiojefiow352okdwofkwkfi address 123.456.789.012
crypto isakmp key 6 9j4ofjwiojefiow352okdwofkwkfi9i42kpfsej09f0 address 123.456.789.012
ccc ddd eee
fff ggg hhh iii
123 456

所以首先我想打印不变(随机行数):

123 345
678 901
bla bla bla
ble ble ble

然后我想打印以 crypto isakmp key 6 开头的 SORTED 行。

最后我想打印文件的其余部分不变(也是随机的行数):

ccc ddd eee
fff ggg hhh iii
123 456

我已经通过许多操作来管理这个问题,包括获取crypto isakmp key 6 的第一个和最后一个位置以及使用tail / head 命令,但它非常复杂,我想知道 AWK/SED 中是否有选项或者其他 linux 工具为指定的行管理它。请分步说明您的命令的作用。

预期输出(加密排序的其余部分完好无损):

123 345
678 901
bla bla bla
ble ble ble
crypto isakmp key 6 9i42kpfsej09f09j4ofjwiojefiow352okdwofkwkfi address 123.456.789.012
crypto isakmp key 6 9j4ofjwiojefiow352okdwofkwkfi9i42kpfsej09f0 address 123.456.789.012
crypto isakmp key 6 kokofeofepokpfowkfpwjeiofjwiojefiow address 123.456.789.012
crypto isakmp key 6 ofjwiojefiow352okdwofkwkfi9i42kpfsej09f09j4 address 123.456.789.012
ccc ddd eee
fff ggg hhh iii
123 456

【问题讨论】:

    标签: linux bash sorting awk sed


    【解决方案1】:

    这是我所做的:

    # get interesting lines with numbers
    LINER1=`grep -n "^crypto isakmp key 6" r1`
    
    # get interesting lines without numbers for later output
    LINER1F=`grep "^crypto isakmp key 6" r1`
    
    # get whole config rows count
    LENGTHR1=`wc -l r1|awk '{print $1}'`
    
    # get 1st interesting line number
    STARTR1=`echo "$LINER1" | head -1 | cut -f 1 -d:`
    
    # get last interesting line number    
    ENDR1=`echo "$LINER1" | tail -1 | cut -f 1 -d:`
    
    # assign 1st segment to variable
    SEGMENT1R1=`head -n $(( $STARTR1 - 1 )) r1`
    
    # assign interesting sorted segment to next variable
    SEGMENT2R1=`echo "$LINER1F"|sort`
    
    # assign last segment to variable
    SEGMENT3R1=`tail -n $(( $LENGTHR1 - $ENDR1 )) r1`
    
    # output whole config with sorted segment to file
    echo "$SEGMENT1R1" > r1
    echo "$SEGMENT2R1" >> r1
    echo "$SEGMENT3R1" >> r1
    

    我希望这可以通过简单的方式完成,无需太多步骤。

    【讨论】:

    • 你已经很好地规划了逻辑。将其转换为awk 代码,但在 cmd 行上列出文件两次,第一次将计算所有变量,第二次以更改的顺序打印出来。根据您的 awk 版本,排序可能比较棘手。您可以使用if (FNR==NR){first time thru} else {2nd time} 来控制正在发生的处理。祝你好运。
    【解决方案2】:

    不完全理解排序的意思,但这会按字母顺序对加密行进行排序,而其他行则保持原样

    asort 函数需要 GNU awk。

    awk 'y=/crypto isakmp key 6/{x=1;a[NR]=$0}
         x&&!y{x=asort(a);for(i=1;i<=x;i++)print a[i];x=0};!x' file
    
    123 345
    678 901
    bla bla bla
    ble ble ble
    crypto isakmp key 6 9i42kpfsej09f09j4ofjwiojefiow352okdwofkwkfi address 123.456.789.012
    crypto isakmp key 6 9j4ofjwiojefiow352okdwofkwkfi9i42kpfsej09f0 address 123.456.789.012
    crypto isakmp key 6 kokofeofepokpfowkfpwjeiofjwiojefiow address 123.456.789.012
    crypto isakmp key 6 ofjwiojefiow352okdwofkwkfi9i42kpfsej09f09j4 address 123.456.789.012
    ccc ddd eee
    fff ggg hhh iii
    123 456
    

    说明

    y=/crypto isakmp key 6/
     #variable y is set to 1 if the line contains this regex, 0 if not
    {
     #The following code block within the brackets is executed if y is non zero
    x=1
     #Set x to 1(i.e true),done every match because it is less hassle and has no negative 
     #side effects 
    a[NR]=$0
     #Create array element in array a with a key of NR(line number,doesn't actually matter what 
     #it is though just has to be unique each line) and a value of $0(the line)
    }
     #End that block
    x&&!y
     #If x(set in the previous block to 1) is set and y isn't (meaning we have encountered a 
     #crypto line but the one we are currently on isn't a crypto line) then
    {
     #Open block like before
    x=asort(a)
     #Sort the array a, and set x to the number of elements
    for(i=1;i<=x;i++)
     #for each element
    print a[i]
     #Print the element , note the loop ends here as we have not enclosed in brackets
    x=0
     #Set x to 0(false)
    }
     #End block
    !x
     #Default action for awk is to print the line if an command returns true, so will print any 
     #line where x is not set or is 0 i.e not crypto lines. We could have also used y'
    

    用有意义的名字

    awk 'InBlock=/crypto isakmp key 6/{Stored=1;Lines[NR]=$0}
         Stored&&!InBlock{
             Count=asort(Lines)
             for(i=1;i<=Count;i++)print Lines[i]
             Stored=0
         }
         !InBlock' file
    

    【讨论】:

    • 似乎工作正常。顺便提一句。我和你的正则表达式中有一个错误,我认为它应该与“^crypto isakmp key 6”一起出现,因为它应该只匹配起始行。您能否逐步解释该命令对解释 !y !x && 等的作用... :)?谢谢。
    • @mike 由于您没有尝试自己回答这个问题,而且这些都是非常基本的命令,我会让您自己弄清楚它们的作用。如果您在查找基本 awk 语法后对脚本的特定部分有任何问题,那么我会解释它们。
    • 我怀疑如果你使用带有几个额外字符的变量名,OP 可能不会那么混乱。像i 这样的单字符变量名称在它们的含义非常明显时很好,但是在像这样的脚本中变量名称axy 不提供任何关于它们代表什么的信息。您应该提到,这需要 GNU awk 用于 asort()
    • 无论哪种方式我都不在乎,我只是建议一种可以修改脚本以使 OP 更容易理解的方法。使用x 来表示两个完全不同的事物(条件为真时设置的标志和asort() 返回的数组中的元素数量)也会使脚本变得比必要的更加混乱。然后,当它在最后被打印否定时,我完全不知道它当时代表什么。
    • 这是一个巨大的改进,远远超出我的预期。现在逻辑很明显了。恕我直言,您可以扔掉所有这些 cmets,因为它们现在完全没有必要了。 wrt 重用 x - 变量名很便宜,不要重载它们 - 这样做绝对没有好处,它只会混淆你的代码。
    【解决方案3】:

    您没有告诉我们您要对什么进行排序,或者您希望它如何排序,或者向我们展示预期的输出,所以这是一个猜测,但也许它是或接近于您想要的:

    $ cat tst.awk
    /crypto isakmp key 6/ {
        buf[$0]
        gotBuf = 1
        next
    }
    gotBuf {
        PROCINFO["sorted_in"] = "@ind_str_asc"
        for (line in buf) {
            print line
        }
        gotBuf = 0
    }
    { print }
    
    $ awk -f tst.awk file
    123 345
    678 901
    bla bla bla
    ble ble ble
    crypto isakmp key 6 9i42kpfsej09f09j4ofjwiojefiow352okdwofkwkfi address 123.456.789.012
    crypto isakmp key 6 9j4ofjwiojefiow352okdwofkwkfi9i42kpfsej09f0 address 123.456.789.012
    crypto isakmp key 6 kokofeofepokpfowkfpwjeiofjwiojefiow address 123.456.789.012
    crypto isakmp key 6 ofjwiojefiow352okdwofkwkfi9i42kpfsej09f09j4 address 123.456.789.012
    ccc ddd eee
    fff ggg hhh iii
    123 456
    

    上面使用了 GNU awk 4.* for sorted_in。

    【讨论】:

    • 只是对加密线进行简单排序(没有附加条件),我附上了输出。
    • 没有“简单排序”之类的东西 - 一切都是使用某些标准和某种顺序对某事物进行排序的。听起来你想对整行进行排序,我猜你想要一个区分大小写的字母升序排序,对吧?我已经更新了我的答案。
    • 是的,按升序排序 :) - 无论如何,我需要对 2 个文件进行排序,使其相互匹配,在这种情况下任何排序都可以,因为它会以相同的方式对两个文件进行排序。我需要这个来比较这些文件。
    • 嗯,如果这是目标,那么我怀疑排序(以及整个脚本)是完全没有必要的,因为您应该只对 2 个文件使用 awk,并在解析第二个文件时测试是否存在于解析第一个文件时创建的哈希表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-19
    相关资源
    最近更新 更多