如果我想执行一个没有设置执行权限的 bash 脚本,我可以这样做:
bash script.sh
bash
如果脚本不可执行,而且我不知道正确的解释器,我应该用什么来代替?是否有命令可以从 shebang 行查找解释器并使用它执行脚本?
答案1
是的。它被称为perl
。以下是一些示例,其中相应的解释器位于文件的 shebang 行中(实际文件扩展名无关紧要):
perl foo.bash # works
perl foo.lua # works
perl foo.clisp # works
perl foo.csh # works
perl foo.php # works
perl foo.gnuplot # works (no arguments)
perl foo.pl # works (obviously)
perl foo.py # works
perl foo.sh # works
perl foo.tcl # works
perl foo.rb # works
perl foo.nodejs # works
perl foo.r # works
perl foo.oct # works
perl foo.csharp # works (no arguments)
这在Perl 的文档:
如果该
#!
行不包含单词“perl”或单词“indir”,则将#!
执行以 命名的程序,而不是 Perl 解释器。这有点奇怪,但它可以帮助那些没有 的机器上的人们#!
,因为他们可以告诉程序他们的 SHELL 是 /usr/bin/perl,然后 Perl 会将程序分派到正确的解释器。
答案2
脚本不一定有shebang
如果脚本是从解释器运行的,你就不能确定它是否根本。从解释器运行的脚本不需要 shebang,如果你调用解释器来运行代码。
因此答案是否定的,没有命令可以确定运行脚本的语言(解释器)。不过,你总是可以查看脚本内部,看看它是否有可以找出答案的东西。
规则简述:
- 运行脚本时,调用解释器总是否决可能的 shebang,无论是否可执行,无论是否是 shebang。
- 如果不可执行则运行从解释器、脚本不需要shebang。
- 如果脚本在运行前没有先调用解释器,它需求(并使用)shebang 来找出要调用哪个解释器,和它需要是可执行的才能具有从其shebang调用解释器的“权限”。
但是,如果脚本没有 shebang,则脚本内部就没有(直接*)信息来告诉要使用哪个解释器。
话说回来
当然,你也可以编写一个包装脚本来尝试找出脚本是否有shebang并从中读取解释器,然后从找到的解释器运行它。
一个例子
#!/usr/bin/env python3
import subprocess
import sys
args = sys.argv[1:]; script = args[0]
try:
lang = open(script).readlines()[0].replace("#!", "").strip().split()[-1]
cmd = [lang, script]+args[1:]
subprocess.call(cmd)
except (PermissionError, FileNotFoundError, IndexError):
print("No valid shebang found")
将其保存为
tryrun
($PATH
例如~/bin
,如果目录不存在,则创建目录,注销并重新登录),将其创建可执行文件.然后运行:tryrun /path/to/nonexecutablescript
在我的不可执行文件
python
和bash
脚本上调用(测试)正确的解释器。
解释
- 该脚本只是读取脚本的第一行,删除
#!
并使用其余部分来调用解释器。 - 如果无法调用有效的解释器,它将引发
PermissionError
或FileNotFoundError
。
笔记
扩展名(.sh
,.py
等)在确定 Linux 上适当的解释器时不起任何作用。
(*当然可以开发一种“智能”猜测算法来从代码中确定语法。)
答案3
您可以使用如下脚本实现此目的:
#!/bin/bash
copy=/tmp/runner.$$
cp $1 ${copy}
chmod u+x ${copy}
${copy}
rm ${copy}
因此:
$ echo "echo hello" > myscript
$ ./myscript
bash: ./myscript: Permission denied
$ ./runscript myscript
hello
我不建议这样做。权限的存在是有原因的。这是一个破坏权限的程序。
请注意,shebang 处理是核心函数(在 Linux 源代码中 -fs/binfmt_script.c
)。从根本上来说,直接调用脚本的进程并不知道#!
——内核会使用它来确定是否需要启动解释器。