使用tac反向读取文件

时间:2013-01-10 13:05:11

标签: linux file unix reverse gnu-coreutils

我是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是否会覆盖输入文件还是将其另存为另一个文件?

2 个答案:

答案 0 :(得分:1)

与大多数UNIX (样式)工具tac一样,它既不会覆盖orignal文件,也不会写入新文件,而是打印到stdout,用{{tac写一个新文件1}}您将使用重定向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 > newfile

答案 1 :(得分:1)

tac只是反转文件的行顺序,因此您需要更强大的功能来完成您想要的任务。此外,所有shell工具都不包括覆盖输入文件的方法,而不使用'temp'文件。某些工具(例如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”启用默认打印。