【Shell编程 / 6】正则表达式与模式匹配(grep、sed、awk)

正则表达式和模式匹配

正则表达式(Regular Expression,即Regex)用于匹配字符串中的特定模式。在 Shell 编程中,正则表达式广泛应用于文本处理和数据过滤。通过正则表达式,可以高效地实现复杂的查找和替换操作。

基本正则表达式

基本正则表达式(Basic Regular Expression, BRE)是一种较为简单的正则表达式形式,主要用于匹配基本的字符串模式。

元字符

基本正则表达式中常用的元字符包括:

  • .: 匹配任意单个字符。
  • *: 匹配前一个字符零次或多次。
  • []: 匹配括号内的任意一个字符。
  • ^: 匹配字符串的开头。
  • $: 匹配字符串的结尾。
  • \: 转义字符,用于匹配特殊字符的本义。

示例

# 匹配包含 "cat" 的行
echo -e "cat\ndog\ncaterpillar" | grep "cat"
# 输出: cat
#        caterpillar

# 匹配以 "cat" 开头的行
echo -e "cat\ndog\ncaterpillar" | grep "^cat"
# 输出: cat

# 匹配以 "dog" 结尾的行
echo -e "cat\ndog\ndoghouse" | grep "dog$"
# 输出: dog

扩展正则表达式

扩展正则表达式(Extended Regular Expression, ERE)比基本正则表达式功能更强大,支持更多的元字符和模式。需要注意的是,某些工具(如 grep)使用扩展正则表达式时需要添加 -E 参数。

额外元字符

扩展正则表达式中新增的元字符包括:

  • +: 匹配前一个字符一次或多次。
  • ?: 匹配前一个字符零次或一次。
  • |: 或运算符,匹配左侧或右侧的模式。
  • ():分组,用于组合模式。

示例

# 匹配包含 "cat" 或 "dog" 的行
echo -e "cat\ndog\nbird" | grep -E "cat|dog"
# 输出: cat
#        dog

# 匹配以 "cat" 开头,后跟零个或多个字母的行
echo -e "cat\ncaterpillar\ncattle" | grep -E "^cat[a-z]*"
# 输出: cat
#        caterpillar
#        cattle

# 匹配包含 "cat" 或 "dog",但只输出匹配部分
echo -e "catdog\ncatfish" | grep -o -E "cat|dog"
# 输出: cat
#        dog

正则表达式在 grep、sed 和 awk 中的应用

在 Shell 编程中,grepsedawk 是处理文本的三大工具,它们都支持正则表达式。

1. grep 中的正则表达式

grep 是一种强大的文本搜索工具,支持基本和扩展正则表达式。

  • 基本正则:

    echo "hello world" | grep "hello"
    # 输出: hello world
    
  • 扩展正则:

    echo -e "cat\ndog\nfish" | grep -E "cat|dog"
    # 输出: cat
    #        dog
    
  • 常用选项:

    • -i: 忽略大小写。
    • -v: 反向匹配。
    • -o: 仅输出匹配的内容。

2. sed 中的正则表达式

sed 是一个流编辑器,常用于文本的查找和替换操作。

  • 基本查找和替换:

    echo "apple banana cherry" | sed 's/banana/orange/'
    # 输出: apple orange cherry
    
  • 全局替换:

    echo "apple banana banana cherry" | sed 's/banana/orange/g'
    # 输出: apple orange orange cherry
    
  • 使用扩展正则:
    添加 -E 参数可以使用扩展正则。

    echo "apple123 banana456" | sed -E 's/[a-z]+[0-9]+/fruit/'
    # 输出: fruit fruit
    

3. awk 中的正则表达式

awk 是一个强大的文本处理工具,可以基于正则表达式对文本进行模式匹配和操作。

  • 匹配特定模式的行:

    echo -e "apple\nbanana\ncherry" | awk '/apple/'
    # 输出: apple
    
  • 条件处理:

    echo -e "apple 10\nbanana 20\ncherry 15" | awk '$2 > 15'
    # 输出: banana 20
    
  • 替换操作:
    使用 gsub 函数进行全局替换。

    echo "apple banana cherry" | awk '{gsub("banana","orange"); print}'
    # 输出: apple orange cherry