如何使用纯 bash 匹配文件中的字符串?

如何使用纯 bash 匹配文件中的字符串?

所以我想匹配文件上的字符串/或单词,但是没有使用任何外部工具(grepsed),仅使用纯 bash...

本质上我想要相当于:

grep "string" file

或者

grep -w "string" file

在纯粹的bash中。

PS:我只关心匹配文件上的精确字符串(带或不带换行符),因此不需要完整的正则表达式支持(其他外部工具可能支持)。

答案1

你能行的。但这是一个非常非常糟糕的主意。它会比以下慢得多(慢几个数量级)grep由于它依赖于特定 shell (Bash) 的功能,因此

这将打印出与作为第一个参数给出的正则表达式模式匹配的行,类似于grep pattern

#!/bin/bash -

regexp="$1"
ret=1
while IFS= read -r line || [ -n "$line" ]; do
  if [[ $line =~ $regexp ]]; then
    printf '%s\n' "$line"
    ret=0
  fi
done
exit "$ret"

将其另存为foo.bash并像这样运行:

foo.bash pattern < inputFile

或者使用标准sh语法,寻找固定字符串而不是正则表达式:

#!/bin/sh -

string="$1"
ret=1
while IFS= read -r line || [ -n "$line" ]; do
  case $line in
    (*"$string"*)
      printf '%s\n' "$string"
      ret=0
  esac
done
exit "$ret"

(将 替换printfexit 0以获得类似于grep -q。)

为了让您了解它有多慢,我创建了一个只有 10001 行的文件,前 5000 行是foo,然后是单个行bar,然后是另一个 5000 行foo

perl -e 'print "foo\n" x 5000; print "bar\n"; print "foo\n" x 5000;' > file

grep现在,比较上面脚本的时间:

$ time grep bar < file
bar

real    0m0.002s
user    0m0.002s
sys     0m0.000s

$ time ./foo.bash bar < file
bar

real    0m0.116s
user    0m0.101s
sys     0m0.016s

正如您所看到的,即使文件很小,差异也很明显。如果我们尝试使用更实质性的脚本,脚本轮流运行的时间几乎难以忍受:

$ perl -e 'print "foo\n" x 500000; print "bar\n"; print "foo\n" x 500000;' > file


$ time grep bar < file
bar

real    0m0.004s
user    0m0.000s
sys     0m0.004s


$ time ./foo.bash bar < file
bar

real    0m11.306s
user    0m10.117s
sys     0m1.188s

然而,这部分是因为 Bash 很慢。标准 sh 版本使用 Dash 运行得更快一些:

$ time dash foo2.sh bar < file
bar

real    0m3.467s
user    0m2.113s
sys     0m1.353s

不过,还是有差距的三个数量级。脚本需要几秒钟的时间,而不是近乎即时的grep.这仍然是一个只有 100 万行、大小约为 4MB 的文件。我希望你能看到问题所在...

相关内容