我应该使用在bash脚本家当? [英] Should I use a Shebang with Bash scripts?
问题描述
我使用bash
回声 $ $ SHELL
/斌/庆典
和开始大约一年前,我停止使用Shebangs我的bash脚本。能够
我受益于使用#!/ bin / sh的
或#!/斌/庆典
?
更新:在某些情况下一个文件只被视为与一个脚本
家当,例如
$猫foo.sh
LS$猫bar.sh
#!/ bin / sh的
LS$文件foo.sh bar.sh
foo.sh:ASCII文本
bar.sh:POSIX shell脚本,ASCII文本可执行
在类UNIX系统上,你应该的总是的开始与家当行脚本。系统调用的execve
(这是负责启动的程序)的依赖于具有或者可执行标头或shebang行的可执行文件的
从FreeBSD的 execve的手册页:
的调用execve()系统调用转换调用进程进入一个新的
处理。新工艺是从一个普通的文件,它的构造
名称由路径指向,被称为新的流程文件。
[...] 这个文件是
无论是一个可执行的目标文件,或跨preTER一个数据文件。 [...] 一个跨preTER文件起始行的形式是: #!除preTER [参数] 当一个跨preTER文件execve'd,系统实际上execve的年代
除指定preTER。如果指定了可选ARG是,它成为
第一个参数间preTER,和原来的名字
execve'd文件成为第二个参数
块引用>同样来自的Linux手册页:
的execve()执行程序中通过文件名指向。文件名必须是
无论是二进制可执行或脚本开始用线的
形式:#!除preTER [可选参数]
块引用>在事实上,如果一个文件没有正确的幻数在它的头,(像一个ELF头或
#!
),的execve
将失败的有(从FreeBSD的手册页的execve再次)的ENOEXEC错误:
[ENOEXEC]新进程文件具有适当的访问
许可,但在一个无效的幻数的
头。
块引用>如果该文件有可执行权限,但没有shebang行,但似乎是一个文本文件,则该行为取决于你正在运行的外壳。
大部分炮弹似乎开始自己的新实例,并给它的文件,请参阅下文。
由于没有保证的脚本,壳牌实际上写的,这可以工作或壮观失败。
(1):
在不明白`#系统!脚本间preTER conven-
和灰壳可编译效仿;看到版本外壳
变量。如果是这样,壳检查文件的第一行,以查看是否
它的形式是`#的!间preTER参数...。如果是,壳开始
除preTER与给定的指定参数和文件饲料给它的标准
输入。
块引用>从FreeBSD的 SH(1):
如果程序不是一个正常的可执行文件(即,如果它
不与幻数的ASCII重新presentation是开始
#!,导致从execve的一个ENOEXEC返回值(2)),但似乎
是一个文本文件,外壳程序将运行的sh国米preT它一个新的实例。从庆典(1):
如果因为该文件不是可执行格式的执行失败,
并且是不是一个目录中,假设该文件是一个外壳脚本,一个
包含shell命令的文件。子shell被产生执行它。
块引用>您不能总是依赖于非标准程序诸如bash的位置。我见过
的/ usr / bin中
,的/ usr / local / bin目录
,庆典的/ opt / FSF /斌
和的/ opt / GNU /斌
仅举几例。所以一般是使用
ENV
是个好主意;#!的/ usr / bin中/ env的庆典
如果你希望你的脚本是便携式的,可以使用
SH
而不是庆典
。#!/ bin / sh的
虽然像POSIX标准做的不能保证的标准公用事业的绝对路径,大多数类UNIX系统似乎有
SH
在/ bin中
和ENV
>的/ usr / bin中。I am using Bash
$ echo $SHELL /bin/bash
and starting about a year ago I stopped using Shebangs with my Bash scripts. Can I benefit from using
#!/bin/sh
or#!/bin/bash
?Update: In certain situations a file is only treated as a script with the Shebang, example
$ cat foo.sh ls $ cat bar.sh #!/bin/sh ls $ file foo.sh bar.sh foo.sh: ASCII text bar.sh: POSIX shell script, ASCII text executable
解决方案On UNIX-like systems, you should always start scripts with a shebang line. The system call
execve
(which is responsible for starting programs) relies on an executable having either an executable header or a shebang line.From FreeBSD's execve manual page:
The execve() system call transforms the calling process into a new process. The new process is constructed from an ordinary file, whose name is pointed to by path, called the new process file. [...] This file is either an executable object file, or a file of data for an interpreter. [...] An interpreter file begins with a line of the form: #! interpreter [arg] When an interpreter file is execve'd, the system actually execve's the specified interpreter. If the optional arg is specified, it becomes the first argument to the interpreter, and the name of the originally execve'd file becomes the second argument
Similarly from the Linux manual page:
execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form:
#! interpreter [optional-arg]
In fact, if a file doesn't have the right "magic number" in it's header, (like an ELF header or
#!
),execve
will fail with the ENOEXEC error (again from FreeBSD's execve manpage):[ENOEXEC] The new process file has the appropriate access permission, but has an invalid magic number in its header.
If the file has executable permissions, but no shebang line but does seem to be a text file, the behaviour depends on the shell that you're running in.
Most shells seem to start a new instance of themselves and feed it the file, see below.
Since there is no guarantee that the script was actually written for that shell, this can work or fail spectacularly.
From tcsh(1):
On systems which do not understand the `#!' script interpreter conven‐ tion the shell may be compiled to emulate it; see the version shell variable. If so, the shell checks the first line of the file to see if it is of the form `#!interpreter arg ...'. If it is, the shell starts interpreter with the given args and feeds the file to it on standard input.
From FreeBSD's sh(1):
If the program is not a normal executable file (i.e., if it does not begin with the "magic number" whose ASCII representation is "#!", resulting in an ENOEXEC return value from execve(2)) but appears to be a text file, the shell will run a new instance of sh to interpret it.
From bash(1):
If this execution fails because the file is not in executable format, and the file is not a directory, it is assumed to be a shell script, a file containing shell commands. A subshell is spawned to execute it.
You cannot always depend on the location of a non-standard program like bash. I've seen bash in
/usr/bin
,/usr/local/bin
,/opt/fsf/bin
and/opt/gnu/bin
to name a few.So it is generally a good idea to use
env
;#!/usr/bin/env bash
If you want your script to be portable, use
sh
instead ofbash
.#!/bin/sh
While standards like POSIX do not guarantee the absolute paths of standard utilities, most UNIX-like systems seem to have
sh
in/bin
andenv
in/usr/bin
.这篇关于我应该使用在bash脚本家当?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!