Bash 正则表达式提取从第 2 次出现的特定字符到行尾的所有文本

Bash Regex extract all text from 2nd occurence of specific character until end of line

我有以下字符串:

text/:some_random_text:text_i_w4nt_to:k33p.until_th3_end_1
text/:some_random_text:text_i_w4nt_to::k33p.until_th3_end_1

用正则表达式,我要提取:

text_i_w4nt_to:k33p.until_th3_end_1
text_i_w4nt_to::k33p.until_th3_end_1

我已经尝试使用 regex101.com 以下表达式:([^:]+)(?::[^:]+){1}$ 并且有效(仅适用于第一个字符串)

但是如果我尝试 bash,它不会

echo "text/:some_random_text:text_i_w4nt_to::k33p.until_th3_end_1" | sed -n "/([^:]+)(?::[^:]+){1}$/p"

使用sed

$ sed s'|\([^:]*:\)\{2\}\(.*\)$||' input_file
text_i_w4nt_to:k33p.until_th3_end_1
text_i_w4nt_to::k33p.until_th3_end_1

$ sed s'|\([^:]*:\)\{2\}||' input_file
text_i_w4nt_to:k33p.until_th3_end_1
text_i_w4nt_to::k33p.until_th3_end_1

使用 cut 没有任何正则表达式会容易得多:

cut -d: -f3- file

text_i_w4nt_to:k33p.until_th3_end_1
text_i_w4nt_to::k33p.until_th3_end_1

sed 不支持非捕获组 (?:,您必须转义 \( \) \{ \}\+

您可以从字符串的开头重复出现 2 次 : 并将其替换为空字符串。

sed 's/^\([^:]\+:\)\{2\}//' file

或使用 sed -E 扩展正则表达式:

sed -E 's/^([^:]+:){2}//' file

输出

text_i_w4nt_to:k33p.until_th3_end_1
text_i_w4nt_to::k33p.until_th3_end_1

没有理由将 sed 或其他外部程序拖入其中;只需使用 bash 的内置正则表达式匹配:

#!/usr/bin/env bash

strings=(text/:some_random_text:text_i_w4nt_to:k33p.until_th3_end_1
         text/:some_random_text:text_i_w4nt_to::k33p.until_th3_end_1)

for s in "${strings[@]}"; do
    [[ $s =~ ^([^:]*:){2}(.*) ]] && printf "%s\n" "${BASH_REMATCH[2]}"
done

哎呀,在 bash:

中不需要正则表达式
printf "%s\n" "${s#*:*:}"

awk

string='ext/:some_random_text:text_i_w4nt_to:k33p.until_th3_end_1
text/:some_random_text:text_i_w4nt_to::k33p.until_th3_end_1'

awk -vFS=: -vOFS=: '{=="";gsub(/^::/,"")}1' <<<"$string"
text_i_w4nt_to:k33p.until_th3_end_1
text_i_w4nt_to::k33p.until_th3_end_1

绝对不需要使用任何需要 regex-backreferences 的东西,因为正则表达式锚定就在行首:

mawk ++NF OFS= FS='^[^:]*:[^:]*:' 
                       
text_i_w4nt_to:k33p.until_th3_end_1
text_i_w4nt_to::k33p.until_th3_end_1