awk 对比grep 与 ??以及要提取的文件的信号线的最佳实践

awk 对比grep 与 ??以及要提取的文件的信号线的最佳实践

我有一个包含多个文件的文件夹。我想.txt根据这些文件的内容创建三个新文件。为了实现这一目标,我想我应该创建begin/end标签来标记文件的不同部分,以用于创建 3 个新文档。

例如,第一个文件的01_FileName.mac结构为:

/* 01_FileName */

/* START HEADER */
 Header 1 Content
/* END HEADER */

/* START SCRIPT */
    Script 1 Content
/* END SCRIPT */

/* START COMMENTS */
    Comments 1 Content
/* END COMMENTS */

同样,第二个输入文件02_FileName.mac

/* 02_FileName */

/* START HEADER */
 Header 2 Content
/* END HEADER */

/* START SCRIPT */
    Script 2 Content
/* END SCRIPT */

/* START COMMENTS */
    Comments 2 Content
/* END COMMENTS */

注意,此类文件超过 2 个。

我想制作以下三份新文件:

  1. Concatenated_Header.txt:

    Header 1 Content
    Header 2 Content
    
  2. Concatenated_Script.txt:

     Script 1 Content
     Script 2 Content
    
  3. Concatenated_Load_Commands.txt:

    push("<NameOfCurrentPath>")$
       load("<NameOfCurrentPath>/01_FileName.mac")$
       load("<NameOfCurrentPath>/02_FileName.mac")$
    

我见过相关的示例,涉及连接特定行或具有特定字符串的行,但不是划分startend的通用方法,以便将各部分组合成新的单独文件。

注意:文件的具体结构实际上并不重要:任何有助于导出这些部分( 、 和 )的文档fileName结构Header ContentScript Content很好Comments Content。目标只是能够将与脚本相关的所有信息存储在单个文件中,同时能够创建这三个新文件。这正是我的想象startend标签可以用来促进这个过程。

(请看这个早期修订了解更多背景和细节)

答案1

awk 'function prnt(type, pr){ print pr >"concatenated_"type".txt"; };
     FNR==1{ type="load";
             if (!path) {
                 path=FILENAME; sub("[^/]+$","",path);
                 prnt(type, "push(\"<"path">\")$");
              };
              prnt(type,"\tload(\"<"FILENAME">\")$");
           };
     /START HEADER/{ prn=1; type="header"; next; };
     /START SCRIPT/{ prn=1; type="script"; next; };
     /END SCRIPT/ || /END HEADER/{ prn=0; };
prn{ prnt(type, $0); }' /home/User/Unix/*.mac

我们定义了一个awk功能;prnt是它的名称,有两个参数,一个用于获取一个短字符串,并用作输出文件名的一部分,该行应写入该行来自pr参数的位置。

function prnt(type, pr){ print pr >"concatenated_"type".txt"; }

参数type值有条件改变;如果是第一行输入FNR==1,我们设置type="load"为记录文件的名称和路径,但是小路应该只写一次,所以我们过去常常if(!path) { path=FILENAME; ...; }确保它会写一次(下次path变量已经取值,所以 if 语句中的块将不会运行小路再次分开)。对于其余的输入,我们将只写入文件名,并且每个文件在FNR==1.

如果一行包含/START HEADER/,我们进行设置,并相应地在它与带有;的行匹配时type="header"进行设置。我们还使用了一个控制变量标志来控制何时调用我们的函数将行打印到专用文件名。type="script"/START SCRIPT/prn=1prn{ prnt(type, $0); }

next命令用于重新开始并读取下一个输入行,因此它不会继续执行以下命令,也不会写入标题起始行输出中的行本身。

我们还重置prn=0标志以避免打印头尾行线。

答案2

$ cat tst.awk
BEGIN {
    out["HEADER"] = "Concatenated_Header.txt"
    out["SCRIPT"] = "Concatenated_Script.txt"
    out["LOAD"]   = "Concatenated_Load_Commands.txt"
}

FNR == 1 {
    if ( NR == 1 ) {
        dir = FILENAME
        sub("/[^/]+$","",dir)
        printf "push(\"%s\")$\n", dir > out["LOAD"]
    }
    printf "   load(\"%s\")$\n", FILENAME > out["LOAD"]
}

block {
    if ( index($0,"/* END ") == 1 ) {
        block=""
    }
    if ( block in out ) {
        print > out[block]
    }
    next
}

index($0,"/* START ") == 1 { block=$3; next }

$ awk -f tst.awk $PWD/*.mac

$ head Concat*
==> Concatenated_Header.txt <==
 Header 1 Content
 Header 2 Content

==> Concatenated_Load_Commands.txt <==
push("/home/foo/tmp")$
   load("/home/foo/tmp/01_FileName.mac")$
   load("/home/foo/tmp/02_FileName.mac")$

==> Concatenated_Script.txt <==
    Script 1 Content
    Script 2 Content

out["COMMENTS"] = "Concatenated_Comments.txt"如果您也想生成注释的输出文件,那么只需在该部分中添加一行即可BEGIN。对于您创建的任何其他内容也是如此START。..END块。请注意,该脚本仅搜索/* START块的外部和/* END内部,两者都仅在行的开头,因此这些字符串可以出现在文本块中,而不会破坏脚本。

相关内容