尝试在文件中的每一行上运行 awk 命令,并将当前行替换为 awk 的结果

Trying to run an awk command on each line in a file, and replace the current line with the results of the awk

提问人:JJRudder 提问时间:7/18/2023 最后编辑:JJRudder 更新时间:7/19/2023 访问量:107

问:

我正在尝试循环浏览一个文件,并使用每一行搜索不同的 csv 文件(特别是搜索第 2 列),并为每个条目返回该文件中的第 4 列。然后,我想用新结果替换当前行。输入文件如下所示:

Ant
Bat
Carp
Dog

目前我正在使用此代码:

while read -r line
do
awk -v line="\"$line\"" -F, '$2 ~ line' search.csv | awk -F, '{print $4}' >> $filename
done < $filename

这会将新行添加到文件的末尾,因此我得到以下输出:

Ant
Bat
Carp
Dog
"Insect"
"Mammal"
"Fish"
"Mammal"

如何只获得第二个列表(引号中的单词)?


编辑:

以下是来自 search.csv 的示例数据:

"A0001","Dog","Canine","Mammal","4","Y","N"

更新#1

search.csv 文件的每个条目都用引号括起来。我是这样编辑我的awk的:

awk -F, 'NR==FNR {wrds["\""$1"\""]; next} $2 in wrds {print ($4 > "temporary.txt")}' "filename.txt" search.csv

现在,它将每行打印一个 0 到屏幕上。临时 .txt 文件仍为空:

0
0
0
0
bash awk while-循环

评论

0赞 markp-fuso 7/18/2023
请用一组 4-6 行的样本来更新问题;同时提供预期结果(确保它与提供的样本相对应)search.csv
0赞 markp-fuso 7/18/2023
循环文件中读取,而双脚本附加同一文件;但随后您声明您只想在输出中看到带引号的单词;你真的想追加到、覆盖或将输出保存到一个完全不同的文件中吗?while/read$filenameawk$filename$filename$filename
1赞 JJRudder 7/19/2023
@markp扶桑:哦,其实这更有意义。我已经尝试过了,它确实有效。谢谢

答:

1赞 anubhava 7/18/2023 #1

你不需要 shell 循环。只需在单个 awk 命令中执行此操作,如下所示:

awk -F, 'NR==FNR {wrds["\"" $1 "\""]; next}
$2 in wrds {print $4 > "tmpFile"}' "$filename" search.csv

手动验证输出,满意后运行:tmpFile

mv tmpFile "$filename"

替换原始输入文件。

评论

1赞 JJRudder 7/19/2023
我已经尝试了这个命令,但它没有做任何事情。没有输出,tmp文件为空: awk -F, 'NR==FNR{wrds[$1];下一页}$2 in wrds{print ($4 > “tmpfile”)}' filename.txt search.csv
0赞 anubhava 7/19/2023
通过编辑您的问题提供示例数据search.csv
1赞 glenn jackman 7/19/2023
@JJRudder,请确保您的文件没有 DOS 样式的行尾\r\n
0赞 anubhava 7/19/2023
此外,还可以更改带引号的单元格值。如果 csv 文件有,则将其更改为"Dog"awkNR==FNR {wrds["\"" $1 "\""]; next}
0赞 anubhava 7/19/2023
@JJRudder:现在试试我更新的答案。
2赞 markp-fuso 7/19/2023 #2

看看OP最新的代码尝试:

awk -F, 'NR==FNR {wrds["\""$1"\""]; next} $2 in wrds {print ($4 > "temporary.txt")}' "filename.txt" search.csv

OP 指出这在终端上生成一个并且是空的。注意:当我运行 OP 的代码时,它确实在控制台上生成了一个,但它甚至没有创建一个名为 .0temporary.txt0temporary.txt

主要问题如下:

print ($4 > "temporary.txt")

哪里:

  • 首先处理 parens 的内容,所以......
  • ($4 > "temporary.txt")作为比较/条件处理,即比较第 4 个字段以查看它是否“大于”文本字符串"temporary.txt"
  • 在这种情况下,and says is not so 结果是 'false',它由 a 表示,所以......$4 == "Mammal"awk"Mammal"> "temporary.txt"awk0
  • 向控制台发送一个(又名“false”)...print0
  • 当然,不会将任何内容写入任何文件(即,不会创建命名的文件,更不用说写入了)temporary.txt

快速解决方法是删除 parens,以便发送到名为 的文件,即:print$4temporary.txt

$ awk -F, 'NR==FNR {wrds["\""$1"\""]; next} $2 in wrds {print $4 > "temporary.txt"}' "filename.txt" search.csv
$              <<=== no ouput, no '0'
$ cat temporary.txt
"Mammal

当您希望脚本将输出发送到动态生成的输出文件集或可变数量时,通常使用从脚本中指定输出文件名称的方法。awkawk

在这种情况下,由于所有输出都转到同一个文件,因此典型的方法是在命令行(即脚本外部)定义输出文件;这往往会使脚本更简洁一些,例如:temporary.txtawkawk

awk -F, 'NR==FNR {wrds["\""$1"\""]; next} $2 in wrds {print $4}' filename.txt search.csv > temporary.txt
                                                      ^^^^^^^^                             ^^^^^^^^^^^^^