将正则表达式应用于标准输入

Ste*_*fan 5 bash regular-expression

在编程中我们经常看到正则表达式的使用。

最常见的形式之一是:

newText = text.replace( /regex/, 'replacementString' )
Run Code Online (Sandbox Code Playgroud)

如果stdin istextstdout is newText,那么 bash 相当于上面的代码是什么?

tan*_*nte 6

对于简单的使用,你可以这样做:

newText=${text/SEARCH/replacement}
Run Code Online (Sandbox Code Playgroud)

因为它是描述在这里,但sed的更复杂的表达式是亚历克斯前面所述的路要走。


Gil*_*il' 6

最直接的答案是seds命令。您需要将 regexp 语法转换为Basic 正则表达式,并且将在每一行上连续应用替换。您可以使用\1through\9来引用原始字符串中带括号的组。添加g修饰符以替换所有出现;否则只替换第一次出现。

sed -e 's/basic regexp/replacement string/g'
Run Code Online (Sandbox Code Playgroud)

更灵活的实用程序是awk。它也默认逐行处理其输入,但您可以更改记录分隔符-vRS=…(标准 awk 需要单个字符,或空值表示两个或多个换行符;Gawk(GNU 版本)接受正则表达式)。该sub函数执行单个替换,并gsub替换所有出现。除了\and之外,替换字符串按字面解释&;如果要引用带括号的组,可以使用matchsubtring函数。

awk '{gsub(/regexp/, "replacement string")}'
Run Code Online (Sandbox Code Playgroud)

Bash 内置了对正则表达式匹配的支持:[[ text =~ regexp ]]. 您可以使用存储在BASH_REMATCH数组中的匹配子字符串构造替换文本。使用readcat获取输入并printf发出输出。以下伪代码执行多次替换(警告,未经测试;代码应该像往常一样从左到右执行多次替换,我希望我做对了)。

# The end marker must not have a prefix that is a suffix of a match of the regexp,
# and must not start or end with a newline
end_marker='EOF'
text=$(cat; echo "$end_marker")
while [[ $text =~ regexp(.*)$ ]]; then
    printf %s%s "${text%"$BASH_REMATCH[0]"}" "replacement string"
    text=$BASH_REMATCH[$#BASH_REMATCH]
  fi
done
printf %s "${text%"$end_marker"}"
Run Code Online (Sandbox Code Playgroud)

(解释几句:结束标记是为了避免被命令替换剥离的尾随换行符。${text%"$BASH_REMATCH[0]"}提取匹配之前的文本部分。请注意,我们不能^(.*)在正则表达式的开头使用,否则我们' d 得到最后一个匹配而不是第一个。匹配后,我们遍历后缀。最后我们打印未匹配的剩余部分,减去结束标记。)

如果您对通配符匹配和有限的替换文本功能感到满意,那么 bash 也有${variable/pattern/replacement}. 将第一个斜杠加倍以替换所有出现的斜杠。如果extglob设置了该选项,模式确实具有正则表达式的功能(但具有不寻常的语法)。