4

我对 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 会覆盖输入文件还是将其保存为不同的文件?

4

2 回答 2

1

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”启用默认打印。

于 2013-01-10T14:40:24.387 回答
1

像大多数 UNIX (样式)工具一样tac,既不会覆盖原始文件也不会写入新文件,它会打印到stdout,与tac您一起写入新文件将使用重定向tac file > newfile,这会将反向保存filenewfile. 你不能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

于 2013-01-10T13:41:11.437 回答