【问题标题】:How do I make shell scripts work on both Linux and OS X?如何使 shell 脚本在 Linux 和 OS X 上都可以工作?
【发布时间】:2026-02-20 10:15:02
【问题描述】:

我有一段代码来编译一个 tex 文档。

#!/usr/bin/env bash

filename="thesis"

pdflatex -shell-escape $filename
makeglossaries $filename
bibtex $filename
pdflatex $filename
pdflatex $filename

# for Ubuntu
#xdg-open $filename.pdf

# for mac
open $filename.pdf

如何让这个脚本在 Linux 和 OS X 上都运行?我觉得应该是这样的,

if is Linux; then
    xdg-open $filename.pdf
elif is OS X; then
    open $filename.pdf
fi

【问题讨论】:

    标签: linux macos shell compatibility


    【解决方案1】:

    检测当前平台的标准方法是调用uname

    uname=$(uname);
    case "$uname" in
        (*Linux*) openCmd='xdg-open'; ;;
        (*Darwin*) openCmd='open'; ;;
        (*CYGWIN*) openCmd='cygstart'; ;;
        (*) echo 'error: unsupported platform.'; exit 2; ;;
    esac;
    "$openCmd" "$filename.pdf";
    

    【讨论】:

    • 不客气。在所有情况下,如果您愿意,您可以删除三个分号中的第一个,也可以删除最后一个双分号(最后一个 case 分支中的那个)。我只是想明确声明终止;我喜欢在所有 bash 语句中包含单个分号终止符,无论它们出现在哪里,并且我喜欢在所有 case 分支上包含双分号。好处之一是它允许您将多个语句连接到一行,而不必担心添加分号。另一个好处是一致性。
    【解决方案2】:

    我建议您尝试进行功能检测,而不是尝试检测操作系统,即在使用未在所有平台上实现的东西之前,尝试检测它是否支持当前平台,不管是什么。你可以这样做如下

    if command -v xdg-open >/dev/null 2>&1; then
        xdg-open $filename.pdf
    elif command -v open >/dev/null 2>&1; then
        open $filename.pdf
    else
        echo >&2 "I don't know how to open the pdf"
    fi
    

    上面的command -v xdg-open >/dev/null 2>&1 将检查名为xdg-open 的程序是否在您的路径中可用。如果是,我们将使用它。否则,我们将尝试不同的选择。

    【讨论】:

    • 这很聪明,+1。但是应该提到的是,这不是 100% 万无一失的。具有相同名称的命令可能存在于不同的平台上,即使它不是预期的命令。对于command -v,即使存在同名的别名或shell 函数也可能导致代码出错。
    • 好点。我不会担心xdg-open,但open 确实太笼统了。