如何遍历字符串以获取来自 linux shell 的模式?

ale*_*lec 3 linux string bash awk split

我有一个脚本可以查看目录中的文件以查找字符串,例如: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'
Run Code Online (Sandbox Code Playgroud)

第一行生成这样的输出:

:politics:violence:
:positivity:
:positivity:somewhat:
:psychology:
:socialServices:family:
:strategy:
:tech:
:therapy:babylon:
:trauma:
:triggered:
:truama:leadership:business:toxicity:
:unfurling:
:tagOne:tagTwo:etcTag:
Run Code Online (Sandbox Code Playgroud)

目标是要获取到的单一列表:tag:的。

同样,问题是如果一行有多个标签,则该行根本不会出现在输出中(与仅显示该行的第一个标签的问题相反)。显然| sed... |那里是有问题的。

**我想把:tagOne:tagTwo:etcTag:它变成:

:tagOne:
:tagTwo:
:etcTag:
Run Code Online (Sandbox Code Playgroud)

等等等等: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
Run Code Online (Sandbox Code Playgroud)

...它有效(对于有限数量的标签),但它会产生奇怪的结果,例如:

:toxicity:p:
:somewhat:y:
:people:n:
Run Code Online (Sandbox Code Playgroud)

...在某些标签的末尾放置奇怪的随机字母,其中标签: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
Run Code Online (Sandbox Code Playgroud)

...具有相同的: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
Run Code Online (Sandbox Code Playgroud)

...根本不分开标签,只是打印如下内容: :truama:leadership:business:toxicity

我应该采取其他方法吗?使用不同的实用程序(可能cut在循环内)?也许在 python 中这样做(我有一些 python 脚本,但不太了解这门语言,但也许这样做很容易)?每次看到awk我都想“EEK!” 所以我更喜欢非 awk 解决方案,更喜欢坚持我使用过的范例以便更好地学习它们。

Jam*_*own 5

使用 PCRE in grep(如果可用)和积极的lookbehind

$ echo :tagOne:tagTwo:tagThree: |  grep -Po "(?<=:)[^:]+:"
tagOne:
tagTwo:
tagThree:
Run Code Online (Sandbox Code Playgroud)

你将失去领先:但仍然获得标签。

编辑:有人提到 awk 吗?:

$ awk '{
    while(match($0,/:[^:]+:/)) {
        a[substr($0,RSTART,RLENGTH)]
        $0=substr($0,RSTART+1)
    }
}
END {
    for(i in a)
        print i
}' file
Run Code Online (Sandbox Code Playgroud)