【问题标题】:How can I detect BSD vs. GNU version of date in shell script如何在 shell 脚本中检测 BSD 与 GNU 版本的日期
【发布时间】:2012-01-05 18:35:48
【问题描述】:

我正在编写一个需要对日期字符串进行操作的 shell 脚本。该脚本应该可以在尽可能多的 *nix 变体中工作,因此我需要处理机器可能具有 BSD 或 GNU 版本日期的情况。

测试操作系统类型的最优雅的方法是什么,以便我可以发送正确的日期标志?

编辑: 澄清一下,我的目标是使用日期的相对日期计算工具,这在 BSD 和 GNU 中似乎不同。

BSD 示例

date -v -1d

GNU 示例

date --date="1 day ago"

【问题讨论】:

  • 检测操作系统类型是没有用的,因为 gnu date 可能安装在 BSD 上,或者从 GNU-Linux 机器上卸载。
  • 好的,知道这很有用。我应该更清楚。我的目标是进行相对日期计算,(我认为)在 GNU 中是使用 -v 完成的,而在 BSD 中则略有不同,但使用 --date。有没有一种通用的方法来做这些日期减法?

标签: shell date gnu bsd


【解决方案1】:

您想检测您正在使用的date 命令的版本,不一定是操作系统版本。

GNU Coreutils date 命令接受--version 选项;其他版本没有:

if date --version >/dev/null 2>&1 ; then
    echo Using GNU date
else
    echo Not using GNU date
fi

但正如 William Pursell 所建议的,如果可能的话,您应该只使用两者共有的功能。

(我认为可用于 GNU date 的选项几乎是可用于 BSD 版本的选项的超集;如果是这种情况,那么假定 BSD 版本的代码应该适用于 GNU 版本.)

【讨论】:

  • +1:这是一个很好的方法,但我会更进一步。如果您担心某个特定选项可能不可用,请尝试一下:如果失败,则将其从您传递到日期的选项字符串中删除。这很快就会变得比只使用 perl 更加乏味。
  • @WilliamPursell:很难想象你想使用某个选项但没有它也能相处的情况。也许如果你想以某种方式格式化日期,但如果它不可用,你可以回退到默认值(这只有在输出是人类可读的时候才有意义)。但这是问题背后的隐含假设,所以...
  • BSD 包含一些在 GNU 上不可用的标志,反之亦然。例如,要从 UTC 转换,BSD 需要 -r 标志,它指向 GNU 的文件。 GNU 可以使用 -d 来完成此任务,而 BSD 上不存在此功能。两者都可以从UTC转换......但我还没有找到它。
  • 问题中明确提到了-v--date,两者均不与其他版本共享,且语法不同。
【解决方案2】:

使用可移植标志。标准可用 here

对于打印相对日期的特殊问题,使用 perl 可能比使用日期更容易:

perl -E 'say scalar localtime(time - 86400)'

(请注意,此解决方案在 23 或 25 小时内完全失败,但许多 perl 解决方案可用于解决该问题。请参阅 perl 常见问题解答。)

但您当然可以使用 Keith 的想法的变体并这样做:

if date -v -1d > /dev/null 2>&1; then
  DATE='date -v -1d'
else
  DATE='date --date="1 day ago"'
fi
eval "$DATE"

或者只是

DATE=$(date -v -1d 2> /dev/null) || DATE=$(date --date="1 day ago")

另一个想法是定义一个要使用的函数:

if date -v -1d > /dev/null 2>&1; then
    date1d() { date -v -1d; }
else
    date1d() { date --date='1 day ago'; }
fi

【讨论】:

  • 有趣的是,这应该出现在关于可移植标准的讨论中,但 perl -E 'say "blah"' 对我不起作用,所以我不得不使用 perl -e 'print "blah\n"'
  • -E 在 5.12 中可用,但在 5.8 中不可用。 (不记得它何时生效,可能在 5.10 系列中。)
  • 你的“或只是”将 BSD 输出发送到 /dev/null,试试DATE=$(date -v 1d 2>/dev/null || date --date="1 day ago")
  • @Lauri 谢谢!剪切-粘贴错误变得猖獗。已编辑
  • 1d 前少了一个连字符,否则会得到当月的第一天。
【解决方案3】:

要回答您的问题,“uname -o”可能就是您想要的。就我而言,它是“GNU/Linux”。您可以自己决定检测操作系统类型是否毫无价值。

【讨论】:

  • BSD 的 uname 不接受 -o 标志。与仅在您的系统上尝试并假设它可以在其他地方工作相比,可移植性更难。在这种情况下,您可以改用 -s 标志。
【解决方案4】:

建议使用基于特征的检测,而不是基于操作系统或平台的检测。

下面的示例代码展示了它是如何工作的:

if is-compatible-date-v; then
    date -v -1d
elif is-compatible-date-d; then
    date --date="1 day ago"
fi
function is-compatible () {
    "$@" >/dev/null 2>&1
}

function is-compatible-date-v () {
    is-compatible date -v +1S
}

function is-compatible-date-d () {
    is-compatible date -d '1 second'
}

我确实需要编写一些 shellcode 来处理 date,并希望代码能够在 date 的 BSD 和 GNU 版本上运行。

我最终得到了一组脚本,为 BSD 和 GNU 版本的 date 提供统一的接口。

例子:

Follow 命令将输出比 2008-10-10 晚 21 天的日期,它适用于 date 的 BSD 和 GNU 版本。

$ xsh x/date/adjust +21d 2008-10-10
2008-10-31

脚本可以在以下位置找到:

它是名为xsh-lib/core 的库的一部分。要使用它们,您需要 repos xshxsh-lib/core,我在下面列出它们:

希望这能帮助有同样需求的人。

【讨论】:

    猜你喜欢
    • 2011-09-02
    • 1970-01-01
    • 2012-03-29
    • 2022-10-17
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 2011-11-22
    • 2017-11-14
    相关资源
    最近更新 更多