【问题标题】:How is it determined which shell runs a script?如何确定哪个 shell 运行脚本?
【发布时间】:2021-12-07 02:39:49
【问题描述】:

我的 Linux 中有几个 shell,比如 bash、sh、zsh...

而且我知道至少有 3 种方法可以指定一个 shell 来执行我的 shell 脚本:

  1. 在shebang中指定,like#!/usr/bash
  2. 执行时在命令行中指定,如sh MyScripts.sh
  3. $SHELL(比如SHELL=zsh)中指定,然后像./MyScripts.sh一样执行脚本

那么,我最大的问题是,当这三种方式之间存在冲突时,哪个规则具有最高优先级?哪个最低?

如果我这样做sh MyScripts.zsh 会怎样?你看,后缀和二进制不匹配。

【问题讨论】:

  • 根据我的实验,似乎Rule#2最高,Rule#3最低。对吗?
  • 如果脚本是可执行的,是否使用SHELL取决于你如何启动脚本。例如,bash 将执行一个本身没有 shebang 的脚本,而不是使用 SHELL 的值。
  • @BenjaminW:(3)一般不起作用,尽管有些程序服从 SHELL 变量。我不会依赖它。 (1) 和 (2) 是安全的。 (2) 很有用,因为您不需要相关脚本的可执行权限,(1) 很有用,因为脚本的用户不必考虑脚本是用什么语言编写的。
  • @user1934428 我只是编辑了问题,没有问它,你的意思是标记我吗?

标签: sh zsh shebang


【解决方案1】:

文件名只是文件名。它们可以是任何东西,除了零字节和/。后缀仅适用于人类。它们可以是任何东西。它们在 Linux 上无关紧要。

当您输入cmd ./filename 时,shell 会执行带有参数./filename 的命令cmd。不管cmdpythonzshbash 还是wc,它都会在第一个参数设置为./filename 的情况下执行。现在程序对 字符串 ./filename 的处理取决于程序。 sh 是一个程序,当它有一个不以 - 开头的参数时,该程序 sh 会读取名为第一个参数的文件并解释其内容。所以sh ./filename./filename 作为sh 脚本执行。

“解释器”是一种程序,旨在以特定的编程语言解释文件的内容。例如程序python 是一个Python 编程语言解释器。 sh 是 POSIX 兼容的 Shell 编程语言的解释器。等等。

当您键入./filename in shell 时,shell (or kernel) 会检查文件是否设置了可执行权限。如果是,它会读取文件的前两个字节。如果文件的前两个字节是#!,则读取到文件第一行的末尾。然后第一行被解释为运行文件名的命令。因此,当您执行./filename 并且您拥有#!anything_here 时,shell 将运行anything_here ./filename

SHELL 在这里无关,有时甚至没有设置。它通常是一个变量,设置为当前解释器的路径。因此,如果您想使用与当前正在运行的解释器相同的解释器运行文件,您可以键入 $SHELL ./filename,这样 shell 就可以扩展变量 SHELL 并以与您正在运行的当前解释器相同的方式运行程序。

【讨论】:

  • 在第 3 段中,如果我在 MyScript.sh 以#!/bin/zsh 开头时执行 sh ./MyScript.sh 会怎样?最后调用哪个解释器?非常感谢!
  • sh ./anything 将执行sh。而cmets以#开头,#!/bin/zsh是shell解释器的注释。
  • ./anything作为第一个参数执行程序sh与以./anything作为输入执行程序sh之间存在差异。
  • 如果我执行./MyScript.sh 而这个 MyScript.sh 是可执行的并且其中没有 shebang 怎么办?将调用哪个解释器?
  • 那么就是ELF文件(二进制文件),如果不是,就会报错。尝试一下似乎微不足道。