使用 grep、awk 和 csv 从文本文件中提取信息

使用 grep、awk 和 csv 从文本文件中提取信息

我正在使用以下代码从一堆文本文件(foo*.txt)中提取信息。

for file in foo*.txt; do 
grep "some_text" $file | tail -n5 | awk '{print $2}' >> bar.csv
done

此注释从一组文件 (foo*.txt) 中打印我想要的数字。当我尝试打印文件名(在 csv 文件的一列中)和数字(在 csv 文件的下一列中)时,我尝试在终端上进行以下操作。

for file in foo*.txt; do 
echo $file
grep "some_text" $file | tail -n5 | awk '{print $2}' >> bar2.csv 
done

这会在终端上打印文件的名称。csv 文件包含我想要的数字。如何修改此代码,以便将文件的名称打印在 csv 文件的一列上,并将提取的数字打印在下一列中?

此代码中的另一个问题是排序问题。例如,考虑文件名 foo_01_s.txt、foo_02_s.txt、foo_03_s.txt.....foo_100_s.txt。如果我想提取信息(使用上述注释),最后一个文件(foo_100_s.txt)不会位于 foo_99_s.txt 之后。

使用 Python/Perl 的解决方案也会有帮助。

答案1

您必须了解您的>>只会重定向当前命令的一部分 - 基本上只是以 开头的命令的结果数字grep,并通过管道传输几次。echo $file是一个单独的命令(您使用;),因此通常会直接发送到 stdout。 您需要做的就是在整个循环之后重定向:

for file in foo*.txt; do 
    echo $file
    grep "some_text" $file | tail -n5 | awk '{print $2}'
done > bar2.csv

如果您想要按“版本”对文件进行排序(这是合适的名称),您可以在排序后列出它们:

for file in $(ls foo*.txt | sort -V); do

对于快速运行一些小文件(运行~1000个文件大概需要几分钟)来说这应该没问题。

编辑

根据您的评论,有几个解决方案。我猜你想要:

file1 1
      2
      3

等等。只需删除echo并修改 echo 行:

for file in foo*.txt; do 
    grep "some_text" $file | tail -n5 | awk -v f=$file '{if(NR==1) {printf("%-20s %-5s\n",f,\$2)} else {printf("%-20s %-5s\n","",$2)}}'
done > bar2.csv

我让awk帮我打印。使用-v允许我传入一个变量f。对于打印,请熟悉printf语法(您可以在 shell 中使用man printf。基本上,我假设两个字段,一个字段为 20,另一个字段为 5,中间有一个空格。负号左对齐。你可以玩它。这将解决您的初始问题,因为现在您可以管道传输该单行。

如果您希望文件只是:

file1,1
file1,2
...
file2,1

您可以删除if我的语句中的awk,或者保留初始解决方案并使用 echo,但使用,

echo -n "$file,"

确保-n不打印换行符。

相关内容