![awk 重复行太多次](https://linux22.com/image/1129023/awk%20%E9%87%8D%E5%A4%8D%E8%A1%8C%E5%A4%AA%E5%A4%9A%E6%AC%A1.png)
我正在使用 awk 创建一个包含文本行并使用数字输入文件的文件。我想替换每个数字一次,即第 1 行获取第一个数字,第 2 行获取第二个数字,第 3 行获取第三个数字。但是,每行都分配了第一个数字,然后每行都分配了第二个数字,依此类推...
这是我的文本输入文件(test.awk):
{printf("\n($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}");
printf("\n($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}");
printf("\n($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1; h=0;}");
}
这是数字的输入文件:
-0.00432739
0.41369093
0.00000000
命令:awk -f test.awk < input.txt > new.txt
生成以下代码,其中三行重复三次:
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1; h=0;}
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1; h=0;}
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1; h=0;}
我想要的是这个:
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1; h=0;}
谁能告诉我如何阻止它将每个数字分配给每一行然后重复这 3 行?
答案1
使用模 3 ( %
) 并进行少许修正printf(\"%%f %%s\n\",$1=="$1",$2)
{
if (NR%3==1) {printf("\n($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}")};
if (NR%3==2) {printf("\n($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}")};
if (NR%3==0) {printf("\n($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1; h=0;}")}
}
如果你的文件中有多于三行代码,那么取模也是一个好主意。上面代码中的input.txt
数字取决于文件中的行数。如果文件中有四行代码,那么你需要类似下面的代码:3
printf
test.awk
printf
{
if (NR%4==1) {printf("\n($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}")};
if (NR%4==2) {printf("\n($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}")};
if (NR%4==3) {printf("\n($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1; h=0;}")};
if (NR%4==0) {printf("\n($2 == \"foo.bar\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1; h=0;}")}
}
输出三条线在input.txt
:
% awk -f test.awk input.txt
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1; h=0;}
输出三行以上在input.txt
% awk -f test.awk input.txt
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1; h=0;}
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1; h=0;}
答案2
您可以使用以下 awk 代码(test.awk):
BEGIN{count=0}{count++}{if(count==1){printf("\n($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",$1=="$1",$2); a=1;}");
printf("\n($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",$1=="$1",$2); a=1;}");
printf("\n($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",$1=="$1",$2); a=1; h=0;}"); }}
答案3
我只需将数字保存在数组中并使用它即可。首先,修改您的数组,test.awk
使其看起来像这样:
($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}
($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}
($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1; h=0;}
您可以用以下命令自动执行此操作:
sed -i 's/^{//;s/}$//;s/printf("\\n//;s/");//' test.awk
完成后,您可以使用此脚本获取输出:
$ awk 'NR==FNR{a[NR]=$1; next}{gsub(/"\$1"/,a[FNR]); print}' input.txt test.awk
($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1==-0.00432739,$2); a=1;}
($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1==0.41369093,$2); a=1;}
($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1==0.00000000,$2); a=1; h=0;}
解释
NR
是当前行号,FNR
是当前文件。因此,只有在读取第一个文件时,两者才相等。因此,awk
上面脚本的第一部分(NR==FNR{a[NR]=$1; next}
)创建一个数组,其键是文件的行号input.txt
,其值是相应的数字。然后它运行next
以移动到下一行,而不执行脚本的第二部分。
第二部分将用数组中存储的第二个文件当前行号的"$1"
值替换字符串( )。结果就是您所要求的。a
FNR
另一种方法是使用一些技巧。不要使用脚本,而是使用paste
来连接文件并awk
进行替换。首先test.awk
按上述方法进行修改,然后:
$ paste input.txt test.awk | awk '{gsub(/"\$1"/,$1);$1="";print;}'
($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1==-0.00432739,$2); a=1;}
($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1==0.41369093,$2); a=1;}
($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1==0.00000000,$2); a=1; h=0;}
解释
该paste
命令将同时打印输入文件的每一行。因此,使用上面的输入,它将打印:
$ paste input.txt test.awk
-0.00432739 ($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}
0.41369093 ($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}
0.00000000 ($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1; h=0;}
然后将其通过 awk 脚本传递,该脚本
- 用于
gsub
将所有出现的 替换为( )"$1"
的值;$1
gsub(/"\$1"/,$1);
- 完成后,
$1
将其设置为空($1=""
),以便第一个文件的数字不会打印在行首。 - 最后,它打印结果行(
print
)。
答案4
Janet,你需要让 awk 知道,在将第一行代码应用到第一个输入行后,它应该跳转到下一个输入行。然后,在应用第二行代码后,它应该跳转到下一个输入行,依此类推。否则,awk 会在每个输入行上应用每一行代码。最简单的方法是在每一行代码后插入一个 getline 命令(除了最后一行之后,因为它没用):
[alessandro@localhost ~]$ cat /tmp/a.awk
{printf("\n($2 == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}");
getline
printf("\n($2 == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1;}");
getline
printf("\n($2 == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\\n\",$1=="$1",$2); a=1; h=0;}");
}
[alessandro@localhost ~]$ cat /tmp/a.txt
-0.00432739
0.41369093
0.00000000
[alessandro@localhost ~]$ awk -f /tmp/a.awk /tmp/a.txt
($2 == "cs.cpool") && (h==1) {printf("%f %s\n",$1==-0.00432739,$2); a=1;}
($2 == "cs.leafc") && (h==1) {printf("%f %s\n",$1==0.41369093,$2); a=1;}
($2 == "cs.dead_leafc") && (h==1) {printf("%f %s\n",$1==0.00000000,$2); a=1; h=0;}[alessandro@localhost ~]$