猫,grep& awk - 同时读取线和&在1循环中读取文件?

时间:2013-09-17 01:56:53

标签: awk while-loop grep cat


嗨,

感谢很多关于stackoverflow的搜索(很棒的资源!)。最近几天我成功完成了这个,甚至成功地解决了以下问题,即输出导致每次运行命令时行数加倍。感谢awk命令能够删除双线。 我在搜索中相当远,但我错过了一个选项。 顺便使用MacosX和linux。

我要做的是解析我的笔记(所有纯文本.md文件),在文本文件中搜索文字/标签(称为greplist.txt)< / em>,并在与searchword / tag 同名的单独文本文件中解析匹配的行(例如@ computer.md)

选择 greplist.txt 的内容为:

@home
@computer
@Next
@Waiting

2个.md文件的示例内容:

school.md:

* find lost schoolbooks @home
* do homework @computer

fun.md

* play videogame @computer

使用此终端命令(效果很好,但还不完美)

$ cat greplist.txt | while read line; do grep -h "$line" *.md >> $line.md.tmp; mv $line.md.tmp $line.md; awk '!x[$0]++' < $line.md > $line.md.tmp && mv $line.md.tmp $line.md ;done

结果

@ computer.md 的结果:

* do homework @computer
* play videogame @computer

@ home.md 看起来像这样

* find lost schoolbooks @home

到目前为止太棒了!对此已经非常满意了。特别是在添加了文件的移动/重命名之后,我也可以在@ tag .md文件中添加额外的任务/行,并且可以包含在文件中,而不会在下次运行命令时被覆盖。 Awesomecakes!

现在我唯一想念的是,我希望在任务后面的@ tag .md文件的输出中,输出还会在搜索结果后面的括号中列出文件名(没有扩展名)(这样nvalt就可以了用它作为内部链接)

因此,示例 @ computer.md 的所需输出将变为:

* do homework @computer [[school]]
* play videogame @computer [[fun]]

我尝试使用grep命令中的-l和-H而不是-h来解决这个问题,但输出它只是在某种程度上变得混乱。 (甚至没有试过添加支架!)

我试过的另一个是这个,但它没有做任何接缝。然而,它确实说明了我正在努力实现的目标。

$ cat greplist.txt | while read line; do grep -h "$line" *.md | while read filename; do echo "$filename" >> $line.md.tmp; mv $line.md.tmp $line.md; awk '!x[$0]++' < $line.md > $line.md.tmp && mv $line.md.tmp $line.md ;done

所以百万津巴布韦元的问题是:如何做到这一点。我尝试过并试过,但这超出了我的技能等级。非常渴望找到解决方案!

提前致谢。

Daniel Dennis de Wit

2 个答案:

答案 0 :(得分:2)

试试这个:

grep -f greplist.txt *.md | awk ' match($0, /(.*).md:(.*)(@.*)/, vars) { print vars[2], "[[" vars[1] "]]" >> vars[3]".md.out"} '

它的作用:

grep 会在 .md 文件的 greplist.txt 中输出匹配的模式:

fun.md:* play videogame @computer
school.md:* find lost schoolbooks @home
school.md:* do homework @computer

最后 awk 会以您想要的格式将文件名移到后面,并将每一行附加到相应的 @ .md.out *文件中:

* play videogame @computer [[fun]]
* find lost schoolbooks @home [[school]]
* do homework @computer [[school]]

我在文件名上添加了 .out ,以便下次执行命令时不会包含@ *文件。

注意,我不确定 awk 脚本是否适用于Mac OS X awk。

答案 1 :(得分:2)

大纲解决方案似乎是编写代码的一种相当冗长的方式。此脚本使用sed编写awk脚本,然后运行awk,以便从标准输入读取其程序并将其应用于所有“.md”文件不要以@开头。

sed 's!.*!/&/ { name=FILENAME; sub(/\\.md$/, "", name); printf "%s [[%s]]\\n", $0, name > "&.md" }!' greplist.txt |
awk -f - [!@]*.md

Mac OS X上的awk版本将从标准输入读取其程序; GNU awk也是如此。因此,它使用在管道上编写程序并从管道读取程序的技术与这些版本一起工作。如果最坏的情况发生,您必须将sed的输出保存到临时文件中,让awk从临时文件中读取程序,然后删除临时文件。将sed替换为awk会很简单,因此您只需要一个awk进程编写awk程序和第二个awk进程执行程序。

生成的awk代码如下:

/@home/ { name=FILENAME; sub(/\.md$/, "", name); printf "%s [[%s]]\n", $0, name > "@home.md" }
/@computer/ { name=FILENAME; sub(/\.md$/, "", name); printf "%s [[%s]]\n", $0, name > "@computer.md" }
/@Next/ { name=FILENAME; sub(/\.md$/, "", name); printf "%s [[%s]]\n", $0, name > "@Next.md" }
/@Waiting/ { name=FILENAME; sub(/\.md$/, "", name); printf "%s [[%s]]\n", $0, name > "@Waiting.md" }

!脚本中使用sed只是选择未出现在生成的脚本中的字符。确定每行上文件的基名是不“有效”的;如果您的文件足够大,您可以添加一行,例如:

{ if (FILENAME != oldname) { name = FILENAME; sub(/\.md$/, "", name); oldname = FILENAME } }

awk脚本的开头(你能想到多少种方法呢?)。然后,您可以删除{-1}}的每行设置。

不要尝试在name文件上运行程序;它会导致混乱。