AWK 从文本文件读取路径

AWK 从文本文件读取路径

我有一个名为路径恢复.txt其中包含一些其他文件的路径。

里面路径恢复.txt

./a2111oi/sky130_fd_sc_hd__a2111oi_0.txt
./a2111oi/sky130_fd_sc_hd__a2111oi_2.txt
./a2111oi/sky130_fd_sc_hd__a2111oi_4.txt 

每个路径都指向另一个具有相同结构的文本文件,如下所示:

HEAD
INFO
BEGIN sky130_fd_sc_hd__a2111oi_0
...
...
END BEGIN
END INFO
END HEAD

我试图从 path_resume.txt 中读取每个 .txt 文件,复制之间的所有行开始结束开始并增量保存到另一个名为output.txt的文件:

BEGIN sky130_fd_sc_hd__a2111oi_0
...
...
END BEGIN
BEGIN sky130_fd_sc_hd__a2111oi_2
...
...
END BEGIN
BEGIN sky130_fd_sc_hd__a2111oi_4
...
...
END BEGIN

当我跑步时:

awk '{while((getline a < $0)> 0) print a}' path_resume.txt

我可以正确读取 path_resume.txt 中的每个文件,但无法删除不需要的行。

当我跑步时:

awk '/BEGIN/{flag=1}/END BEGIN/{flag=0}flag' ./a2111oi/sky130_fd_sc_hd__a2111oi_0.txt
 >> output.txt

我可以删除不需要的行,但是我必须手动传递文件的路径。我不知道如何合并这两个命令来实现我的目标。我很感激任何帮助。

答案1

您可以使用循环内的打印/无打印标志构建相同的逻辑while(getline)。像这样的东西:

awk '{ while((getline a < $0) > 0) { 
    if (a ~ /BEGIN/) p=1;
    if (p) print a;
    if (a ~ /END BEGIN/) p=0;
} }' path_resume.txt > output.txt

这里唯一的事情是您需要显式使用if语句,而不是像在 AWK 脚本顶层那样使用隐式条件。

或者在 Bash 中,将文件名列表放入一个数组中,然后将它们一次性全部传递给 AWK:

readarray -t filenames < path_resume.txt
awk '/BEGIN/ {p=1}; p; /END BEGIN/ {p=0}' "${filenames[@]}" > output.txt

(我将打印操作放在END BEGIN检查之前,以打印结束分隔符。)

答案2

像下面这样的东西,未经测试,将使用任何 awk 做你想做的事情:

awk '
    NR == FNR { ARGV[ARGC++]=$0; next }
    $1 == "BEGIN" { f=1 }
    f
    $0 == "END BEGIN" { f=0 }
' path_resume.txt > output.txt

或者这可能会稍微快一点,但请参阅http://awk.freeshell.org/AllAboutGetline这样你就不会陷入getline不必要或错误使用的陷阱:

awk '
    BEGIN {
        file = ARGV[--ARGC]
        while ( (getline line < file) > 0 ) {
            ARGV[ARGC++] = line
        }
    }
    $1 == "BEGIN" { f=1 }
    f
    $0 == "END BEGIN" { f=0 }
' path_resume.txt > output.txt

答案3

使用xargs(并且不使用 doubleawk从文件中读取每一行)您可以传递文本文件中的所有路径:

xargs awk  '/BEGIN/{flag=1}/END BEGIN/{print;flag=0}flag'  < path_resume.txt > out.txt

我假设你的文件路径恢复.txt任何路径中不包含空格

awk曾经{print;flag=0}也打印过该行END BEGIN


如果您的路径的文件名中包含空格,那么您可以使用以下命令:

tr '\n' '\0' < path_resume.txt | xargs -0  awk  '/BEGIN/{flag=1}/END BEGIN/{print;print "";flag=0}flag' > out.txt

答案4

这种方法怎么样?这有点懒,但它会完成这项工作。您阅读以下行并将每一行用作path_resume.txt一个文件来使用awk

for i in `cat path_resume.txt`; do awk '/BEGIN/{flag=1}/END BEGIN/{flag=0}flag' $i >> output; done

相关内容