在shell配置脚本中,如何解释BSD上的coreutils与GNU之间的差异?


9

到本月为止,我的shell配置非常简单(主要是a .bashrc.bash_profile主要带有一些别名),但是我一直在对其进行重构,以便根据我是否使用zsh和bash来获得不同的行为。他们首先获取一个通用的shell配置文件,该文件应适用于任何情况,然后专门针对所使用的特定shell(我对此进行符号链接)。

今天ls停止工作时,我感到很惊讶。原来,在重构期间.bashrc,有一个别名

alias ls='ls --color=always'

ls在OSX的Terminal上用bash 破坏了东西。一旦我看到BSD ls喜欢-G彩色,但是GNU(或Ubuntu上的任何东西)喜欢--color,很明显,很多选择是不同的。

我的问题是,解决BSD和GNU coreutils之间的选项差异的最佳方法是什么?我是否应该在if块中测试一个env变量,以查看正在使用的操作系统并应用正确的行为?还是为每个操作系统制作单独的配置文件更有意义?

尽管对这些问题的回答可能是主观的,但似乎BSD和GNU coreutils之间差异范围的缩小和解决这些问题以使通用配置可在大多数* nix上使用的策略将是相当客观的。


更改壳不会解决任何问题,并且与ls -c有所不同ls --color。编辑了您要解决的问题。
Mikel 2014年

Answers:


9

编写支持不同操作系统的脚本的唯一可靠方法是仅使用POSIX定义的功能。

对于诸如您的个人外壳配置之类的事情,您可以使用适合您特定用例的技巧。如下所示是很丑陋的,但可以实现目标。

if ls --version 2>/dev/null | grep -q 'coreutils'; then
    alias ls='ls --color=always'
else
    alias ls='ls -G'
fi

我一直在尝试不同的方法,我认为您的“丑陋”解决方案非常好,甚至没有那么丑陋。事实证明,我之前没有注意到ls选项的不匹配,因为我使用的是Ports的GNU coreutils。这是一个示例,为什么在$ OSTYPE上执行'if'可能无法传递期望的结果。
迷宫

当不存在GNU coreutils(但仍然能够测试coreutils)时,是否有一种方法可以抑制来自“ if ls --version”的错误?
迷宫

哦,没关系抑制错误。我只是在将管道传递到grep之前将stderr重定向到/ dev / null,并且它可以按我的意愿工作。
迷宫

3
除了coreutils明确寻找之外,为什么不测试颜色标记是否起作用,例如if ls --color=auto -d / >/dev/null 2>&1; then ...
Mikel 2014年

@mikel如果只关注颜色(如示例中所示),那很好。如果您还关心其他功能,则检查coreutils很有用。
jordanm 2014年

3

if语句填充代码以对coreutils类型进行切换确实可行,但是处理不同类型的干净编程解决方案是使用多态。由于这是Bash,因此我们本身没有多态性,但是我一直在寻找一种伪造它的方法。唯一的要求是将.bashrc文件等组织成函数。

首先,我为coreutils平台类型创建一个测试:

get_coreutils_platform() {
    local ls_version="$(ls --version 2>/dev/null)"
    if [[ "$ls_version" == *"GNU coreutils"* ]]; then
        echo gnu
    else
        echo bsd
    fi
}

然后我们可以根据类型进行分派:

platform=$(get_coreutils_platform)
define_standard_aliases_$platform
configure_shell_vars_$platform

这是BSD的实现:

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(请注意,我们使用CLICOLOR变量来打开颜色,而不是使用alias,这看起来更干净了)

GNU实现

define_standard_aliases_gnu() {
    define_standard_aliases
    alias ls='ls --color=auto'
}

configure_shell_vars_gnu() {
    configure_shell_vars
}

为了完整起见,下面是“抽象库”的示例实现:

define_standard_aliases() {
    alias ll='ls -l'
    alias l.='ls -d .*'
}

configure_shell_vars() {
    export EDITOR=vim
}

这要干净得多,除非您使用的是0.1%的系统,例如装有GNU ls但未安装GNU cat(也许它确实很旧,并且它们具有fileutils但没有textutils)。我很想ls在您的调度程序中使用,而不是cat,尤其是因为您的别名都不涉及cat
Mikel 2014年

另外,您不需要--color=auto第二和第三别名,因为第一个别名将该选项添加到中ls
Mikel 2014年

1
@Mikel哇,我完全没意识到alias是递归的。这使我使示例更加简单。
Michael Kropat 2014年

好多了。:-)
Mikel 2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.