【问题标题】:Unable to use -C of grep in Unix Shell Script无法在 Unix Shell 脚本中使用 grep 的 -C
【发布时间】:2018-02-27 03:43:05
【问题描述】:

我可以在普通命令行中使用grep

grep "ABC" Filename -C4

这给了我所需的输出,即匹配模式线上方和下方 4 行。

但如果我在 Unix shell 脚本中使用相同的命令,我将无法 grep 模式上方和下方的行。它给了我输出作为模式匹配的唯一行,最后一个错误不能说无法打开grep-C4

如果我使用-A4-B4,结果是相似的

【问题讨论】:

  • uname -srv 的输出更新你的Q。我打赌您使用的是旧版本的 SunOS(或许多其他版本),其中 -[ABC] 选项不可用。但是由于它适用于您的 cmd 行,您需要输入 which grep 然后在脚本中使用像 /path/to/ABCgrep/grep 这样的完整路径,或者覆盖像 export PATH="/path/to/ABCgrep/grep:$PATH" 这样的 PATH 设置。祝你好运。
  • 将选项放在文件名之前:grep -C4 "ABC" Filename。如果这也不起作用,那么您正在运行与 shell 脚本运行的 grep 不同的 grep — 您需要为您使用的 grep 找到正确的路径并在脚本中使用它。 -A-B-C 选项是 GNU 扩展; o/s 命令可能不支持它们。您没有确定您正在使用的平台——如果是 Linux,那不会是问题,但如果是 Solaris、AIX 或 HP-UX,则可能是问题。由于您没有使用 Linux 标签,因此您使用的可能不是 Linux。

标签: unix scripting grep


【解决方案1】:

我假设您需要一个没有 GNU 扩展的可移植 POSIX 解决方案(-C NUM-A NUM-B NUM 都是 GNU,模式和/或文件名后面的参数也是如此)。

POSIX grep 不能这样做,但 POSIX awk 可以。这可以被调用,例如grepC -C4 "ABC" Filename(假设它被命名为“grepC”,是可执行的,并且在你的$PATH中):

#!/bin/sh

die() { echo "$*\nUsage: $0 [-C NUMBER] PATTERN [FILE]..." >&2; exit 2; }

CONTEXT=0  # default value

case $1 in
  -C  ) CONTEXT="$2"; shift 2 ;;        # extract "4" from "-C 4"
  -C* ) CONTEXT="${1#-C}"; shift ;;     # extract "4" from "-C4"
  --|-) shift ;;                        # no args or use std input (implicit)
  -*  ) [ -f "$1" ] || die "Illegal option '$1'" ;;  # non-option non-file
esac

[ "$CONTEXT" -ge 0 ] 2>/dev/null || die "Invalid context '$CONTEXT'"
[ "$#" = 0 ] && die "Missing PATTERN"

PATTERN="$1"
shift

awk '
  /'"$PATTERN"'/ {
    match='$CONTEXT'
    for(i=1; i<=CONTEXT; i++) if(NR>i) print last[i];
    print
    next
  }
  match { print; match-- }
  { for(i='$CONTEXT'; i>1; i--) last[i] = last[i-1]; last[1] = $0 }
' "$@"

这会将die 设置为致命错误函数,然后从您的参数(-C NUMBER-CNUMBER)中找到所需的上下文行,不支持的选项会出错(除非它们是文件)。

如果上下文不是数字或没有模式,我们再次致命错误。

否则,我们保存模式,将其移开,并保留其余选项以作为文件 ("$@") 交给 awk。

在这个 awk 调用中有三个节:

  1. 匹配模式本身。这需要结束字符串的单引号部分以合并$PATTERN 变量(如果通过awk -v 导入,该变量可能无法正确运行)。在那次匹配时,我们将上下文的行数存储到match 变量中,循环遍历保存在last 哈希中的前几行(如果我们已经走得足够远,可以得到它们),然后打印它们。然后我们跳到下一行而不评估其他两节。
  2. 如果有匹配,我们需要接下来的几行作为上下文。当这节打印它们时,它会递减计数器。新的比赛(上一节)将重置该计数。
  3. 我们需要保存之前的行以便在匹配时调用。这会循环遍历我们关心的上下文行数,并将它们存储在 last 哈希中。当前行($0)存储在last[1]中。

【讨论】:

    猜你喜欢
    • 2012-06-30
    • 1970-01-01
    • 2013-12-15
    • 1970-01-01
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 1970-01-01
    相关资源
    最近更新 更多