1

你好,

由于最近几天在stackoverflow(很棒的资源!)上进行了大量搜索,我成功了,甚至在以下问题中也成功了,这是每次我运行命令时输出导致行数加倍。感谢能够删除双线的 awk 命令。我的搜索距离很远,但缺少 1 个选项。顺便说一下,同时使用 MacosX 和 linux。

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

greplist.txt的内容选择有:

@home
@computer
@Next
@Waiting

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

学校.md:

* find lost schoolbooks @home
* do homework @computer

有趣的.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

到目前为止太棒了!已经真的很高兴了。特别是由于添加了文件的移动/重命名,我还可以将额外的任务/行添加到 @ 标记 .md 文件中,并包含在文件中而不会在下次运行命令时被覆盖。很棒的蛋糕!

现在我唯一想念的是,我希望在任务后面的@标记.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

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

提前致谢。

丹尼尔·丹尼斯·德维特

4

2 回答 2

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从临时文件中读取程序,然后删除临时文件。将 替换为 很简单sedawk因此您将有一个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脚本的开头(你能想到多少种方法呢?)。然后,您可以删除name.

不要试图在@topic.md文件上运行程序;它会导致混乱。

于 2013-09-17T14:36:27.217 回答
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 上运行。

于 2013-09-17T09:48:22.533 回答