通过bash myscript.sh vs ./myscript.sh启动一个bash脚本

时间:2015-03-05 13:08:42

标签: linux bash shell

有两种方法可以从Linux CLI执行bash脚本。

你要么:

bash myscript.sh

或:

./myscript.sh

起初我认为两种方法都是相同的。但是我在工作中注意到sudo bash被系统管理禁用(即我需要root权限才能执行此操作),而sudo ./没有问题。

通过bash myscript.sh./myscript.sh启动脚本有什么区别?有没有允许用户通过sudo bash myscript.sh执行脚本同时允许他执行./myscript.sh的逻辑解释?

4 个答案:

答案 0 :(得分:2)

这解决了内核查找和执行您刚输入的命令的方式。

如果当前目录中有文件,则使用

执行该文件
./file

内核检查文件的权限,然后检查文件的第一行,如果找到shebang line,它就会使用它。正确的Bash脚本应该有#!/bin/bash或可能#!/usr/bin/env bash,其中二进制文件的路径在不同系统上可能不同(可能您的系统上有/usr/bin/bash/usr/local/bin/bash中的Bash )。

(如果文件中没有executable permission,则只会出现错误,并忽略该文件的内容。)

如果文件位于PATH上的目录中,则无需指定其路径(在前一种情况下是相对路径 - ./表示当前目录中的路径“),它不需要在当前目录中。

bash

bash上的某个位置找到名为PATH的二进制文件(可能在/bin/bash之类的某个位置)并执行该二进制文件。在没有shebang行的情况下,将检查文件的magic marker,在这种情况下是ELF二进制魔术标记,因此调用执行该类文件的例程。作为最终回退,文件将传递给用户的默认shell,如下所述。

最后,

bash ./file

bash file

启动bash并将file作为其第一个参数。 (在后一种情况下,file也可以是PATH上的文件。)这可以有两个结果;

  • 该文件包含有效的Bash脚本,并且已执行。
  • 该文件包含其他内容,但无论如何它都被解释为Bash命令。

还有

sh file

仅当文件包含sh命令时才是正确的,bash命令是sh允许的命令的子集。使用sh执行Bash脚本是一个相当常见的错误(使用bash执行正确的sh文件很好,虽然有些浪费,因为Bash与{{1}向后兼容})。

关于sudo,允许sudo ./script没有意义,因为用户只需创建一个包含bash -i的脚本即可获得root权限。也许禁止sudo bash只是为了温和地推动特权用户不要过分夸大他们的特权(但如果他们不理解轻推,那么显然不能达到预期的目的;显然,安全性该系统已经非常值得怀疑了。)

答案 1 :(得分:2)

bash myscript.sh

这会在新进程中运行bash(必须位于PATH的一部分目录中)并指示它(假设bash引用Bash shell)到加载并执行myscript.sh(必须位于PATH或该进程'当前工作目录中的一部分的目录中)。请注意,在这种情况下,始终会bash用于解释myscript.sh的内容。

./myscript.sh

这会运行./myscript.sh。在此过程中,将检查文件的shebang行。该脚本使用该行中指定的shell或使用默认shell(在SHELL环境变量或/etc/passwd中指定)在新进程中执行。因此,在这种情况下,实际的程序解释myscript.sh可能会有所不同。

答案 2 :(得分:0)

在当前shell中使用./hello.bash并输入enter时,会发生在系统

strace -ff -p 4768 #PID OF MY MAIN SHELL
Process 4768 attached
read(0, ".", 1)                         = 1
write(2, ".", 1)                        = 1
read(0, "/", 1)                         = 1
write(2, "/", 1)                        = 1
read(0, "h", 1)                         = 1


write(2, "h", 1)                        = 1
read(0, "e", 1)                         = 1
write(2, "e", 1)                        = 1
read(0, "\t", 1)                        = 1

stat("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/home/tux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/home/tux/programming", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
stat("/home/tux/programming/bash", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
openat(AT_FDCWD, "/home/tux/programming/bash/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3

getdents(3, /* 5 entries */, 32768)     = 128 

geteuid()                               = 1000
getegid()                               = 1000
getuid()                                = 1000
getgid()                                = 1000
access("./hello.bash", X_OK)            = 0
stat("./hello.bash", {st_mode=S_IFREG|0775, st_size=32, ...}) = 0
geteuid()                               = 1000
getegid()                               = 1000
getuid()                                = 1000
getgid()                                = 1000
access("./hello.bash", R_OK)            = 0
clone(Process 4998 attached
[pid  4998] execve("./hello.bash", ["./hello.bash"], [/* 55 vars */]) = 0

从我的想法,shell检查文件是否存在使用stat系统调用以及执行权限和读取权限,之后你可以看到一个新进程开始使用clone syscall创建,之后脚本开始在新进程中执行,我认为一切都发生在用户空间中,内核唯一做的就是系统调用并在链接器的帮助下将proccess图像加载到内存中

答案 3 :(得分:-2)

当PATH变量不包含目录路径时,使用./script.sh执行Bash脚本是唯一的方法。如果是这样,它也可以通过script.sh执行。