AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 448692
Accepted
StoneThrow
StoneThrow
Asked: 2018-06-09 10:20:22 +0800 CST2018-06-09 10:20:22 +0800 CST 2018-06-09 10:20:22 +0800 CST

为什么“ps ax”找不到没有“#!”的正在运行的 bash 脚本 标题?

  • 772

当我运行这个脚本时,打算运行直到被杀死......

# foo.sh

while true; do sleep 1; done

...我无法使用以下方法找到它ps ax:

>./foo.sh

// In a separate shell:
>ps ax | grep foo.sh
21110 pts/3    S+     0:00 grep --color=auto foo.sh

...但是如果我只是将常见的“ #!”标题添加到脚本中...

#! /usr/bin/bash
# foo.sh

while true; do sleep 1; done

...然后脚本变得可以通过相同的ps命令找到...

>./foo.sh

// In a separate shell:
>ps ax | grep foo.sh
21319 pts/43   S+     0:00 /usr/bin/bash ./foo.sh
21324 pts/3    S+     0:00 grep --color=auto foo.sh

为什么会这样?
这可能是一个相关的问题:我认为“ #”只是一个评论前缀,如果是这样,“ #! /usr/bin/bash”本身只不过是一个评论。但是“ #!”是否具有比仅仅作为评论更大的意义?

shell-script shell
  • 3 3 个回答
  • 4003 Views

3 个回答

  • Voted
  1. Best Answer
    Kusalananda
    2018-06-09T10:29:27+08:002018-06-09T10:29:27+08:00

    当当前的交互式 shell 是bash,并且您运行没有#!-line 的脚本时,bash将运行该脚本。该过程将在ps ax输出中显示为 just bash。

    $ cat foo.sh
    # foo.sh
    
    echo "$BASHPID"
    while true; do sleep 1; done
    
    $ ./foo.sh
    55411
    

    在另一个终端:

    $ ps -p 55411
      PID TT  STAT       TIME COMMAND
    55411 p2  SN+     0:00.07 bash
    

    有关的:

    • 哪个 shell 解释器运行没有 shebang 的脚本?

    相关部分构成bash手册:

    如果由于文件不是可执行格式而导致执行失败,并且文件不是目录,则假定它是一个 shell script,一个包含 shell 命令的文件。 产生一个子shell来执行它。这个子 shell 重新初始化自己,因此效果就像调用了一个新的 shell 来处理脚本一样,除了父级记住的命令的位置(参见下面的 SHELL BUILTIN COMMANDS 下的哈希)由子级保留。

    如果程序是以 开头的文件#!,则第一行的其余部分指定程序的解释器。 shell 在自己不处理这种可执行格式的操作系统上执行指定的解释器。[...]

    这意味着./foo.sh在命令行上运行,当foo.sh没有#!-line 时,与在子 shell 中运行文件中的命令相同,即

    $ ( echo "$BASHPID"; while true; do sleep 1; done )
    

    用正确的#!线指向 eg /bin/bash,它就像在做

    $ /bin/bash foo.sh
    
    • 14
  2. Gilles 'SO- stop being evil'
    2018-06-09T10:48:23+08:002018-06-09T10:48:23+08:00

    当 shell 脚本以 开头时#!,就 shell 而言,第一行是注释。然而,前两个字符对系统的另一部分有意义:内核。这两个字符#!被称为shebang。要了解 shebang 的作用,您需要了解程序是如何执行的。

    从文件执行程序需要内核的操作。这是作为execve系统调用的一部分完成的。内核需要验证文件权限,释放与当前在调用进程中运行的可执行文件相关的资源(内存等),为新的可执行文件分配资源,并将控制权转移给新程序(以及更多我就不提了)。系统调用替换当前运行进程的execve代码;有一个单独的系统调用fork来创建一个新进程。

    为了做到这一点,内核必须支持可执行文件的格式。该文件必须包含机器代码,以内核理解的方式组织。shell 脚本不包含机器代码,因此不能以这种方式执行。

    shebang 机制允许内核将解释代码的任务推迟到另一个程序。当内核看到可执行文件以 开头时#!,它会读取接下来的几个字符并将文件的第一行(减去前导#!和可选空格)解释为另一个文件的路径(加上参数,我不会在这里讨论) )。当内核被告知要执行该文件/my/script,并且它看到该文件以该行开头时#!/some/interpreter,内核/some/interpreter将使用参数执行/my/script。然后由它/some/interpreter来决定/my/script它应该执行的脚本文件。

    如果一个文件既不包含内核理解格式的本机代码,也不以 shebang 开头怎么办?好吧,那么该文件是不可执行的,并且execve系统调用失败并显示错误代码ENOEXEC(可执行格式错误)。

    这可能是故事的结尾,但大多数 shell 都实现了回退功能。如果内核返回ENOEXEC,shell 会查看文件的内容并检查它是否看起来像一个 shell 脚本。如果 shell 认为文件看起来像一个 shell 脚本,它会自己执行它。它如何做到这一点的细节取决于外壳。ps $$您可以通过添加脚本来查看正在发生的一些事情,还可以通过查看进程,strace -p1234 -f -eprocess其中 1234 是 shell 的 PID。

    在 bash 中,这种回退机制是通过调用fork而不是execve. 子 bash 进程自行清除其内部状态并打开新的脚本文件以运行它。因此,运行脚本的进程仍然使用原始 bash 代码映像和最初调用 bash 时传递的原始命令行参数。ATT ksh 的行为方式相同。

    % bash --norc
    bash-4.3$ ./foo.sh 
      PID TTY      STAT   TIME COMMAND
    21913 pts/2    S+     0:00 bash --norc
    

    相比之下,DashENOEXEC通过调用/bin/sh作为参数传递的脚本的路径来做出反应。换句话说,当您从 dash 执行 shebangless 脚本时,它的行为就好像该脚本有一个带有#!/bin/sh. Mksh 和 zsh 的行为方式相同。

    % dash
    $ ./foo.sh
      PID TTY      STAT   TIME COMMAND
    21427 pts/2    S+     0:00 /bin/sh ./foo.sh
    
    • 12
  3. schily
    2018-06-09T10:28:58+08:002018-06-09T10:28:58+08:00

    在第一种情况下,脚本由当前 shell 的一个分叉子运行。

    您应该首先运行echo $$,然后查看以您的 shell 的进程 id 作为父进程 id 的 shell。

    • -1

相关问题

  • 打印文件行及其长度的脚本[关闭]

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 按分隔符拆分并连接字符串问题

  • 如何将带有〜的路径保存到变量中?

  • MySQL Select with function IN () with bash array

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve