【问题标题】:using tac to read a file in reverse使用 tac 反向读取文件
【发布时间】:2012-12-24 21:09:09
【问题描述】:

我是 UNIX 编码的新手,我有一个需要逐行反向读取的文件。该文件在 {} 中有代码段。然后我需要以这个反向文件作为输入来运行一个 awk 脚本。我正在让我们的支持人员安装 tac,但在他们这样做之前,我想知道它是否会输出我需要的东西,或者是否有人可以提出替代方案。

该文件的数据格式为:

page 0 0 0 none
{
   layer 0 0 0 "1line" 0 8 8 3
   {
      sector 0 -1 0 32 
      {
        point_name 0 0 34543 34 44 1 1 0
        status 1 0 1 0 1 431232 "transformer" 23 12
        analog 1 0 1 0 1 321234 11.5 43 1 1 0
        ...
        ...
        ...
        device 1 0 1 "ground" 32 56 1 1 0
      }
    }
}

我想保留 {} 但反转 {} 之间的行,所以输出看起来像:

page 0 0 0 none
{
   layer 0 0 0 "1line" 0 8 8 3
   {
      sector 0 -1 0 32 
      {
        device 1 0 1 "ground" 32 56 1 1 0
        ...
        ...
        ...
        analog 1 0 1 0 1 321234 11.5 43 1 1 0
        status 1 0 1 0 1 431232 "transformer" 23 12
        point_name 0 0 34543 34 44 1 1 0
      }
    }
}

另外,tac 会覆盖输入文件还是将其保存为不同的文件?

【问题讨论】:

    标签: linux file unix reverse gnu-coreutils


    【解决方案1】:

    像大多数 UNIX (style) 工具tac 既不会覆盖原始文件也不会写入新文件,它会打印到stdout,以使用tac 写入新文件,您将使用重定向tac file > newfile 这会将反向的file 保存到newfile。你不能单独使用tac 做你需要的事情,你需要一个脚本。

    这是awk中的一个:

    {
        # store each line in the array line
        line[n++] = $0
    } 
    
    /{/ {
        # get the line number of the last line containing {
        first=NR
    }
    
    !/}/ {
        # get the line number of the last line not containing }
        last=NR
    } 
    
    END {
        # print first section in order
        for (i=0;i<first;i++) 
            print line[i]
        # print second section in reverse order
        for (i=last-1;i>=first;i--)    
            print line[i]
        # print last section in order
        for (i=last;i<NR;i++) 
            print line[i]
    }
    

    将此保存到文件中,例如 reverse,然后运行 ​​awk -f reverse file

    $ awk -f reverse file
    page 0 0 0 none
    {
       layer 0 0 0 "1line" 0 8 8 3
       {
          sector 0 -1 0 32 
          {
            device 1 0 1 "ground" 32 56 1 1 0
            ...
            ...
            ...
            analog 1 0 1 0 1 321234 11.5 43 1 1 0
            status 1 0 1 0 1 431232 "transformer" 23 12
            point_name 0 0 34543 34 44 1 1 0
          }
        }
    }
    

    使用重定向创建一个新文件awk -f reverse file &gt; newfile

    【讨论】:

    • 如果不进行一些修改,除了给出的确切输入之外,这将失败 - 这可能不是 OP 想要的。我会帮你解决它,但这真的不是你想要解决这个问题的方式。另外,现在是凌晨 2 点 30 分,我要睡觉了……晚上。
    • @steve 我理解这个问题的方式,代码格式很好,} 从来没有出现在{ 之前,所以我保持脚本简单易懂。
    【解决方案2】:

    tac 只是颠倒文件的行序,因此你需要更强大的东西来完成你想要的。此外,所有 shell 工具都不包括在不使用“临时”文件的情况下覆盖输入文件的方法。某些工具(例如sedPerl 等)具有所谓的“就地编辑”选项,当未提供备份文件后缀时,将给出文件覆盖的最终结果。

    要完成您想要的,我建议使用awk。运行如下:

    awk -f script.awk file > newfile
    

    要使用临时文件覆盖您的输入文件,请运行:

    awk -f script.awk file > temp && mv temp file
    

    script.awk的内容:

    /{/ {
        print (a ? a ORS : "") $0
        f=1; a=b=""
        next
    }
    
    f && !/}/ {
        a = (a ? a ORS : "") $0
        b = $0 (b ? ORS b : "")
        next
    }
    
    /}/ && b {
        print b ORS $0
        a=b=f=""
        next
    }1
    

    结果:

    page 0 0 0 none
    {
       layer 0 0 0 "1line" 0 8 8 3
       {
          sector 0 -1 0 32 
          {
            device 1 0 1 "ground" 32 56 1 1 0
            ...
            ...
            ...
            analog 1 0 1 0 1 321234 11.5 43 1 1 0
            status 1 0 1 0 1 431232 "transformer" 23 12
            point_name 0 0 34543 34 44 1 1 0
          }
        }
    }
    

    或者,这是一个班轮:

    awk '/{/ { print (a ? a ORS : "") $0; f=1; a=b=""; next } f && !/}/ { a = (a ? a ORS : "") $0; b = $0 (b ? ORS b : ""); next } /}/ && b { print b ORS $0; a=b=f=""; next }1' file
    

    解释:

    第一个代码块询问该行是否包含左大括号。如果是这样,打印记录 'a' 中的任何内容,然后是当前记录(包含左大括号的行)。设置一个标志,删除记录'a'和'b'并跳过处理其余代码。

    当且仅当标志已设置并且该行不包含右括号时,才会执行第二个块。现在我们建立两个记录'a'和'b'。回想一下,如果一行包含左大括号,将打印记录'a'。所以它必须建立在“开始到结束”的方向。然后我们在“从头到尾”方向构建记录“b”。 'next' 然后跳过处理其余代码。

    如果该行包含右大括号和记录'b',则将执行第三个块(请记住,这是反向构建的记录)。然后我们打印记录'b',后跟当前行(带有右大括号的行)。删除记录“a”、“b”并重置标志。 'next' 跳过处理其余代码。末尾的“1”启用默认打印。

    【讨论】:

    • @sudo_O:我已经添加了解释。不过说实话,代码比解释更有意义(至少对我来说)。 HTH。
    • 感谢你们的快速回复,我稍后会尝试他们,如果他们解决了我的问题会告诉你们
    猜你喜欢
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    相关资源
    最近更新 更多