半新手。尝试使用 awk 脚本实现自动化。理论上应该很简单。
文件集,全部以 .lst 结尾。每个文件中都有一行(数百行)带有特定的字符串 - 比如说单词“Wall”。我希望做的是最终得到一个文件,其中每行以(i)文件名和(ii)输出字符串结尾。我有“部分”单独工作,但还没有弄清楚如何将它们组合在一起(以生成通用输出文件)。
所以,假设我有 3 个 *.lst 文件(file1.lst、trash.lst、blah.lst)。我可以使用类似以下内容将文件名输出到文件中(毫无疑问有更好的方法,但它有效......):
ls -l *.lst | awk '{ print "File: " $9 }' > filenames.dat
而且,可以轻松地将每个 *.lst 文件中包含“Wall”的行输出到公共文件,使用类似以下内容:
awk '/Wall/{print}' *.lst > wallvals.dat
我可以通过各种方式对两者进行后处理和合并,但我想弄清楚如何使用 awk 在一行中完成这一切。因此,生成的输出文件可能如下所示:
File: file1.lst Wall data 4.54
File: trash.lst Wall data 3.44
File: blah.lst Wall data 333.66
我尝试过各种管道方法,或者在 awk 参数中嵌套各种位 - 但我尝试过的任何方法都不起作用(除非目的是生成错误消息)。
提前赞赏明显的指针......
答案1
当前正在处理的文件的文件名awk
可在特殊变量中找到FILENAME
。这意味着您可以awk
像这样调整第二个命令:
awk '/Wall/ { printf "%s:%s\n", FILENAME, $0 }' *.lst
或者,如果你不喜欢printf
,
awk '/Wall/ { print FILENAME ":" $0 }' *.lst
或者,通过使用输出字段分隔符OFS
,
awk -v OFS=: '/Wall { print FILENAME, $0 }' *.lst
这会输出文件名和与模式匹配的行,中间有一个冒号。
这与以下grep
命令的作用相同:
grep -H 'Wall' *.lst
...有一个微小的区别,即此处的搜索字符串用作基本正则表达式而不是扩展正则表达式(但这在本例中并不重要)。该-H
选项不是标准的,如果grep
给出多个文件名则没有必要。grep 'Wall' /dev/null *.lst
将是编写相同命令的更标准方法(如果给出多个路径名,实用程序总是输出每个匹配的文件名)。
如果你想要精确的您在问题中提到的输出格式,然后修改printf
格式字符串:
awk '/Wall/ { printf "File: %s\t%s\n", FILENAME, $0 }' *.lst
或者,
awk '/Wall/ { print "File: " FILENAME "\t" $0 }' *.lst
这会输出字符串File:
,后跟文件名、制表符和行。
关于你的第一个命令:它是一般来说解析 的输出是一个坏主意ls
,部分是因为它几乎总是不必要且不雅观,部分是因为 的输出ls
主要用于查看(文件名可能对其进行了额外的格式化)。它几乎总是意味着您将无法读取所有有效的文件名。看为什么*不*解析`ls`(以及该怎么做)?