如何在 Linux 下使用 egrep 或 ksh 确定预匹配和后匹配

如何在 Linux 下使用 egrep 或 ksh 确定预匹配和后匹配

我正在办公室处理 Linux 系统上运行的一个问题。我希望能够使用 egrep 或 ksh 模式匹配来确定匹配的字符串,而且还需要能够确定匹配前和匹配后的字符串。

我知道我可以在 Perl 中做到这一点,但我还希望能够使用 egrep 或 ksh 模式匹配来做到这一点。

我进行了一些 Google 搜索,找到了一个 egrep 命令,您可以在其中指定预匹配和后匹配字符的数量,但这还不够好。我需要完整的预匹配和后匹配字符串。

答案1

grep

你可以使用 Perl 的\K使用选项启用与 Perl 兼容的正则表达式-P)和展望模式如下:

$ echo -e "pre1 line1 post1\npre2 line2 post2" |
grep -Po "pre2.*\Kline.(?=.*post2)"
line2

...其中查找和评估模式pre2.*和但未包含在匹配输出中,但在输入行中相同序列中的所有三个模式成功匹配后,模式将打印在输出中。.*post2line.

在 shell 中

bash以及 和其他类似的 Bourne 类 shell 中kshzsh您可以执行类似以下操作:

pat="line."
pre="pre2.*"
post=".*post2"

echo -e "pre1 line1 post1\npre2 line2 post2" |
while IFS= read -r line
  do
    [[ "$line" =~ $pre$pat$post ]] && echo "$line"
    done
### Outputs "pre2 line2 post2"
### You can echo "$pat" as well

grep -Po或者在文件上模拟上述输出,使用如下函数:

mygrep () {

pre="${1}.*"
pat="$2"
post=".*${3}"
file="$4"
help="Usage: mygrep \"prematch\" \"match\" \"postmatch\" \"filename\""

if [[ $# -lt 4 ]]
  then
    echo "$help"
    return
    fi

while IFS= read -r line
  do
    if [[ "$line" =~ $pre$pat$post ]]
      then
        for word in $line;
          do
            [[ "$word" =~ $pat ]] && echo "$word" && break
            done
      fi
    done < "$file"
    
}

... 其工作原理如下:

$ cat file
pre1 line1 post2
pre2 someword line2 otherword post2
pre3 line3 nomatch post3
pre2 match match line4 will match post2
pre2 post2
pre2 nomatch post2
$
$
$ mygrep --help
Usage: mygrep "prematch" "match" "postmatch" "filename"
$
$
$ mygrep "pre2" "line." "post2" "./file"
line2
line4

注意$line循环头部未加引号的参数for是故意的,目的是允许 shell 进行单词拆分,以便可以循环遍历输入行中的单个单词,但要知道,如果该行中的一个单词恰好包含任何 glob 字符,这也将允许 shell 对当前工作目录中的文件名进行 globbing,因此在这种情况下,您可能需要首先读取单词 (按空格分割)将该行放入一个数组中并将它们作为数组元素进行循环,同时引用该数组元素的扩展……这将是更安全在这种情况下 (出于教育原因) ... 像这样:

mygrep () {

pre="${1}.*"
pat="$2"
post=".*${3}"
file="$4"
help="Usage: mygrep \"prematch\" \"match\" \"postmatch\" \"filename\""

if [[ $# -lt 4 ]]
  then
    echo "$help"
    return
    fi

while IFS=' ' read -r -a line
  do
    if [[ "${line[*]}" =~ $pre$pat$post ]]
      then
        for word in "${line[@]}";
          do
            [[ "$word" =~ $pat ]] && echo "$word" && break
            done
      fi
    done < "$file"
    
}

注意另外,尽管 shell 可以使用 glob 模式或正则表达式模式来匹配文本,但这并不是最好的选择……请改用grep或类似……不过,您可能想阅读可以使用 globbing 来搜索文件内容吗?

相关内容