我应该使用在bash脚本家当? [英] Should I use a Shebang with Bash scripts?

查看:121
本文介绍了我应该使用在bash脚本家当?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用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 of bash.

#!/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 and env in /usr/bin.

这篇关于我应该使用在bash脚本家当?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆