有两种方法可以从Linux CLI执行bash脚本。
你要么:
bash myscript.sh
或:
./myscript.sh
起初我认为两种方法都是相同的。但是我在工作中注意到sudo bash
被系统管理禁用(即我需要root权限才能执行此操作),而sudo ./
没有问题。
通过bash myscript.sh
与./myscript.sh
启动脚本有什么区别?有没有允许用户通过sudo bash myscript.sh
执行脚本同时允许他执行./myscript.sh
的逻辑解释?
答案 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
上的文件。)这可以有两个结果;
还有
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执行。