我有一个脚本,该脚本可以在目录中的文件中查找字符串,例如:tagName:
对单个标记有效,:tag:
但对多个:tagOne:tagTwo:tagThree:
标记无效。
我当前的脚本可以:
grep -rh -e '^:\S*:$' ~/Documents/wiki/*.mkd ~/Documents/wiki/diary/*.mkd | \
sed -r 's|.*(:[Aa-Zz]*:)|\1|g' | \
sort -u
printf '\nNote: this fails to display combined :tagOne:tagTwo:etcTag:\n'
第一行正在生成这样的输出:
:politics:violence:
:positivity:
:positivity:somewhat:
:psychology:
:socialServices:family:
:strategy:
:tech:
:therapy:babylon:
:trauma:
:triggered:
:truama:leadership:business:toxicity:
:unfurling:
:tagOne:tagTwo:etcTag:
而目标是要获取到的单一列表:tag:
的。
同样,问题是如果一行包含多个标签,则该行根本不会出现在输出中(与之相反的问题是,仅显示该行的第一个标签)。显然| sed... |
那里是有问题的。
**我想:tagOne:tagTwo:etcTag:
变成这样:
:tagOne:
:tagTwo:
:etcTag:
等等用:politics:violence:
等
冒号不是必需的,tagOne
也比冒号好(也许更好,但这是微不足道的):tagOne:
。
该问题是,如果一个行有多个标签,该行根本不会出现在输出(而不是仅仅是只有行的第一个标签被显示的问题)。显然| sed... |
那里是有问题的。
所以我应该用sed
更好的东西代替...
我已经试过:
智慧的sed:
grep -rh -e '^:\S*:$' ~/Documents/wiki/*.mkd ~/Documents/wiki/diary/*.mkd | \
sed -r 's|(:[Aa-Zz]*:)([Aa-Zz]*:)|\1\r:\2|g' | \
sed -r 's|(:[Aa-Zz]*:)([Aa-Zz]*:)|\1\r:\2|g' | \
sed -r 's|(:[Aa-Zz]*:)([Aa-Zz]*:)|\1\r:\2|g' | \
sort -u
...适用(仅适用于有限数量的标签),但它会产生奇怪的结果,例如:
:toxicity:p:
:somewhat:y:
:people:n:
...在某些标签的末尾放置奇怪的随机字母,其中:p:
最后一个字符是:leadership:
标签,“领导力”不再出现在列表中。与:y:
和相同:n:
。
我还尝试了几种方式使用循环...
grep -rh -e '^:\S*:$' ~/Documents/wiki/*.mkd ~/Documents/wiki/diary/*.mkd | \
sed -r 's|(:[Aa-Zz]*:)([Aa-Zz]*:)|\1\r:\2|g' | \
sed -r 's|(:[Aa-Zz]*:)([Aa-Zz]*:)|\1\r:\2|g' | \
sed -r 's|(:[Aa-Zz]*:)([Aa-Zz]*:)|\1\r:\2|g' | \
sort -u | grep lead
...也有:leadership:
丢失标签等问题。就像...
for m in $(grep -rh -e '^:\S*:$' ~/Documents/wiki/*.mkd ~/Documents/wiki/diary/*.mkd); do
for t in $(echo $m | grep -e ':[Aa-Zz]*:'); do
printf "$t\n";
done
done | sort -u
...根本不分隔标签,只打印类似以下内容的内容:
:truama:leadership:business:toxicity
我应该采取其他方法吗?使用其他实用程序(也许cut
在循环内)?也许是在python中做的(我有一些python脚本,但是对语言不太了解,但是这样做很容易)?每次看到时,awk
我都会想“ EEK!” 因此,我希望使用非简单的解决方案,而是坚持使用我所使用的范例以更好地学习它们。
直通tr
可以将这些字符串拆分为单独的行:
grep -hx -- ':[:[:alnum:]]*:' ~/Documents/wiki{,/diary}/*.mkd | tr -s ':' '\n'
这也将删除冒号,并且输出中将出现一个空行(易于修复,请注意,由于前导,该空行将始终是第一个:
)。添加sort -u
以排序并删除重复项,或awk '!seen[$0]++'
删除不进行排序的重复项。
使用以下方法sed
:
sed '/^:/!d;s///;/:$/!d;s///;y/:/\n/' ~/Documents/wiki{,/diary}/*.mkd
这也消除冒号,但避免了添加空行(通过除去前/后:
与s
使用前y
音译剩余:
到<newline>
)。sed可以与tr结合使用:
sed '/:$/!d;/^:/!d;s///' ~/Documents/wiki{,/diary}/*.mkd | tr -s ':' '\n'
使用awk
与工作:
分开场,删除重复:
awk -F: '/^:/ && /:$/ {for (i=2; i<NF; ++i) if (!seen[$i]++) print $i}' \
~/Documents/wiki{,/diary}/*.mkd
伟大的贡献,我喜欢这种简单。将中间的内容
:
转换为换行符正是我所知道的必须存在的简单性!!!这给了我:grep -rh -e '^:\S*:$' ~/Documents/wiki/diary/*.mkd | tr -s ':' '\n' | sort -u
一个简单的单行代码,没有无法理解的PCRE,并且从...grep -Po...
答案中看不到正面(还有我不想独自冒险的学习漏洞)。所以谢谢 :)你知道我为什么能做
grep... *.mkd | tr -s ':' '\n' | sort -u
但是不知道grep ...*.mkd | sed 's|:|\r|g' | sort -u
吗?在我看来,那完全是可以互换的tr
,sed
但那只是sed
断点。进行更改会导致我在问题中提到的同类奇怪的破损/问题。@alec很高兴提供帮助。
tr -s
提供对重复字符的特殊处理(在任何音译之后将其“压缩”为单个字符)。@alec该sed命令正在使用
\r
而不是\n
。sed 's|:|\n|g'
会起作用,但会在输出中产生多余的空行。我的天啊!就是这样!谢谢!难怪
sed
一直如此神秘地表现!!!我想我vim
对插入新行的语法感到困惑:/