Linux 和 Solaris 的通用 grep 方法

Universal approach to grep for both Linux and Solaris

我有一个相对较长的脚本集合,我目前正在评估这些脚本,并对源代码进行更改以便在 Linux 和 SunOS 框中执行相同的脚本集。部分代码有一个简单的 grep,如下所示:

#Linux
echo -e  "\n foo \n bar \n test ok" | grep -Evw 'foo|bar'

如果翻译为:

,我的移植尝试工作正常
#SunOS
echo -e  "\n foo \n bar \n test ok" | /usr/xpg4/bin/grep -Ev 'foo|bar'

有没有办法在 Bash 中编写一条语句以在两种情况下工作?或者,我是否应该做好心理准备开始为每个操作系统实施额外的 if/else 语句?

在这种情况下,似乎 /bin/grep 可以同时进行正则表达式和单词匹配,但是使用 /usr/bin/grep 我们只能进行单词而不是两者:

$ echo -e  "\n foo \n bar \n test ok" | grep -Evw 'foo|bar'
grep: illegal option -- E
Usage: grep [-c|-l|-q] -bhinsvw pattern file . . .
$ echo -e  "\n foo \n bar \n test ok" | /usr/xpg4/bin/grep -Evw 'foo|bar'
Usage:  grep [-c|-l|-q] [-bhinsvwx] pattern_list [file ...]
    grep [-c|-l|-q] [-bhinsvwx] [-e pattern_list]... [-f pattern_file]... [file...]
    grep -E [-c|-l|-q] [-bhinsvx] pattern_list [file ...]
    grep -E [-c|-l|-q] [-bhinsvx] [-e pattern_list]... [-f pattern_file]... [file...]
    grep -F [-c|-l|-q] [-bhinsvx] pattern_list [file ...]
    grep -F [-c|-l|-q] [-bhinsvx] [-e pattern_list]... [-f pattern_file]... [file...]

如何将类似的东西放在脚本的顶部:

[ -d /usr/xpg4/bin ] && PATH="/usr/xpg4/bin:$PATH"

那么以下行将在两个系统上都有效:

echo -e  "\n foo \n bar \n test ok" | grep -Evw 'foo|bar'

这个想法当然是检查目录 /usr/xpg4/bin 是否存在,如果存在,我们可以假设它包含一个 grep 支持我们想要的选项(大概是 GNU grep).因此,只需将该目录添加到 $PATH 的开头,使其具有最高优先级。

一个解决方案是在 shebang 之后放置 :

grep_path=/usr/lib/gnu/bin # <- EDIT ME
PATH=$grep_path:$PATH

# will work on any platform with a GNU grep
grep foobar file

Is there a way to write a single statement in Bash to work in both scenarios?

是的。

Or, should I be mentally prepared to start implementing additional if/else statements for each operating system?

不,应该尽可能避免这种情况。在您的情况下,一切都可以使用标准命令完成,因此无需添加 OS 特定代码。

这是一种可移植的方法。这应该适用于所有类似 Unix 的机器:

PATH=`getconf PATH`:$PATH # Should be done once at the beginning of scripts.

printf "\n foo \n bar \n test ok" | grep -Ev '\<foo\>|\<bar>\'

getconf PATH 正在向所有 Unix/Unix 类似实现的 POSIX 兼容命令返回路径。

printf 应该在需要格式化命令时使用,echo 不能可靠地使用,因为它的行为未定义,即使在 POSIX 下也是如此。

\<...\> 是 POSIX 使用扩展正则表达式指定单词边界的方法。

请注意,我没有使用 $(getconf PATH),而是使用较旧的 `getconf` 语法,因为在 Solaris 10 上,您可能 运行 遗留的 Bourne shell。