AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 489628
Accepted
Harold Fischer
Harold Fischer
Asked: 2018-12-18 23:37:26 +0800 CST2018-12-18 23:37:26 +0800 CST 2018-12-18 23:37:26 +0800 CST

为什么 POSIX 未指定 `#!` 语法的行为?

  • 772

从POSIX 规范的Shell 命令语言页面:

如果 shell 命令文件的第一行以字符“#!”开头,则结果未指定。

为什么#!POSIX 未指定行为?我感到莫名其妙的是,如此便携和广泛使用的东西会有一个未指定的行为。

shell posix
  • 3 3 个回答
  • 2552 Views

3 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2018-12-18T23:57:05+08:002018-12-18T23:57:05+08:00

    我认为主要是因为:

    • 实施之间的行为差​​异很大。有关所有详细信息,请参阅https://www.in-ulm.de/~mascheck/various/shebang/。

      然而,它现在可以指定大多数类 Unix 实现的最小子集:比如#! *[^ ]+( +[^ ]+)?\n(只有一个或两个单词中的可移植文件名字符集中的字符)其中第一个单词是本机可执行文件的绝对路径,事情不是如果可执行文件是 setuid/setgid,则太长并且行为未指定,并且实现定义了解释器路径或脚本路径是否传递argv[0]给解释器。

    • POSIX 并没有指定可执行文件的路径。几个系统在/bin/中具有 pre-POSIX 实用程序,/usr/bin并且在其他地方具有 POSIX 实用程序(例如在 Solaris 10 上,其中/bin/sh是 Bourne shell 而 POSIX 位于/usr/xpg4/bin;Solaris 11 将其替换为更符合 POSIX 的 ksh93,但其他大多数中的工具/bin仍然是古老的非 POSIX 工具)。有些系统不是 POSIX 系统,但具有 POSIX 模式/仿真。所有 POSIX 要求是有一个记录的环境,系统在其中运行 POSIXly。

      例如,参见 Windows+Cygwin。实际上,在 Windows+Cygwin 中,当脚本由 cygwin 应用程序调用时,she-bang 会受到尊重,而不是由本机 Windows 应用程序调用。

      因此,即使 POSIX 指定了 shebang 机制,它也不能用于编写 POSIX sh// ... 脚本(另请注意,shebang 机制不能用于编写可靠的sed/脚本,因为它不允许传递选项结束标记)。awksedawk

    现在它未指定的事实并不意味着你不能使用它(好吧,它说#!如果你希望它只是一个常规评论而不是一个she-bang,那么你不应该从第一行开始),但是如果你这样做,POSIX 不给你任何保证。

    根据我的经验,使用 shebangs 比使用 POSIX 编写 shell 脚本的方式为您提供更多的可移植性保证:放弃 she-bang,以 POSIXsh语法编写脚本,并希望调用脚本的任何内容都调用符合 POSIX 的脚本sh,即如果您知道脚本将在正确的环境中由正确的工具调用,那么很好,但不是这样。

    您可能必须执行以下操作:

    #! /bin/sh -
    if : ^ false; then : fine, POSIX system by default
    else
      # cover Solaris 10 or older. ": ^ false" returns false
      # in the Bourne shell as ^ is an alias for | there for
      # compatibility with the Thompson shell.
      PATH=`getconf PATH`:$PATH; export PATH
      exec /usr/xpg4/bin/sh - "$0" ${1+"$@"}
    fi
    # rest of script
    

    如果您想移植到 Windows+Cygwin,您可能必须使用.bat或.ps1扩展名命名您的文件,并使用一些类似的技巧cmd.exe来powershell.exe调用sh同一文件上的 cygwin。

    • 22
  2. JdeBP
    2018-12-19T05:26:05+08:002018-12-19T05:26:05+08:00

    [T] 他的行为在所有 POSIX 投诉 shell 之间似乎是一致的。我认为这里不需要回旋余地。

    你看的不够深入。

    早在 1980 年代,这种机制实际上并没有标准化。尽管 Dennis Ritchie 已经实施了它,但该实施尚未在 AT&T 的宇宙中向公众传播。它实际上只在 BSD 中公开可用并为人所知;在 AT&T Unix 上不可用的可执行 shell 脚本。因此,将其标准化是不合理的。这个当代的 doco 就是这种事态的例证,它是许多这样的例子之一:

    请注意,BSD 允许直接执行开头的文件#! interpreter,而 SysV 只允许直接执行 a.out 文件。这意味着exec…()可能必须在 SysV 下更改 BSD 程序中的一个例程的实例,以改为执行该/bin/sh程序的解释器(通常)。
    ——斯蒂芬·弗雷德(1988 年)。“在 System X Release Y 上编程”。澳大利亚 Unix 系统用户组通讯。第 9 卷,第 4 期。111.

    这里重要的一点是您正在查看 shell,而可执行的 shell 脚本的存在实际上是exec…()函数的问题。shell 所做的包括可执行脚本机制的前身,即使在今天仍然可以在某些 shell 中找到(现在也被强制用于exec…p()功能子集),并且有些误导。在这方面,标准需要解决的是exec…()解释脚本如何工作,而在最初创建 POSIX 时,它根本无法在目标操作系统的主要部分中工作。

    一个从属的问题是为什么此后没有标准化,尤其是在 1990 年代之交,脚本解释器的幻数机制已经在宇宙的 AT&T 方面向公众传播并已exec…()在系统 5 接口定义中记录下来:

    解释器文件以以下形式的一行开头

    #!路径名 [arg]
    其中pathname是解释器的路径,arg是可选参数。当你exec一个解释器文件时,系统exec是指定的解释器。
    — exec. System V 接口定义。第 1 卷。1991 年。

    不幸的是,今天的行为几乎与 1980 年代一样大相径庭,并且没有真正常见的行为可以标准化。一些 Unices(例如著名的 HP-UX 和 FreeBSD)不支持将脚本作为脚本的解释器。第一行是由空格分隔的一个、两个还是多个元素,这在 MacOS(以及 2005 之前的 FreeBSD 版本)和其他之间有所不同。支持的最大路径长度会有所不同。 ␀POSIX 可移植文件名字符集之外的字符和前导和尾随空格一样棘手。第 0、第 1 和第 2 个参数的最终结果也很棘手,系统之间存在显着差异。一些当前符合 POSIX 但不符合-Unix 系统仍然不支持任何这样的机制,并且强制它会将它们转换为不再符合 POSIX 标准。

    进一步阅读

    • 哪个 shell 解释器运行没有 shebang 的脚本?
    • 在这种情况下,为什么我可以将参数传递给 /usr/bin/env?
    • script. NetBSD 杂项信息手册。2005-05-06。
    • https://unix.stackexchange.com/a/605761/5132
    • 11
  3. jamesdlin
    2018-12-19T23:10:35+08:002018-12-19T23:10:35+08:00

    正如其他一些答案所指出的那样,实现方式各不相同。这使得标准化和保持与现有脚本的向后兼容性变得困难。即使对于现代 POSIX 系统也是如此。例如,Linux 没有用空格完全标记 shebang 行。macOS 不允许脚本解释器成为另一个脚本。

    另见http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability

    • 1

相关问题

  • 这个命令是如何工作的?mkfifo /tmp/f; 猫/tmp/f | /bin/sh -i 2>&1 | 数控 -l 1234 > /tmp/f

  • FreeBSD 的 sh:列出函数

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • grep -v grep 有什么作用

  • 如何将带有〜的路径保存到变量中?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve