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
    • 最新
    • 标签
主页 / server / 问题 / 739664
Accepted
Soviero
Soviero
Asked: 2015-11-30 19:28:33 +0800 CST2015-11-30 19:28:33 +0800 CST 2015-11-30 19:28:33 +0800 CST

Bash shell 脚本在通过标准输入传递到 LXC 容器时乱序执行

  • 772

我将以下简单的 shell 脚本传递给 LXC 容器上的 bash:

apt-get update
apt-get install postgresql -y

sudo -u postgres psql -c 'create database dvdrental;'

我用来运行它的实际命令是:

cat sample.sh | lxc-attach -n test-container -- /bin/bash

我这样做而不是将脚本上传到容器并以这种方式执行的原因是,这只是我们正在构建的一个更复杂的应用程序的概念证明,它必须通过标准输入接收命令并运行它们在容器中。

它似乎工作得很好,除了一件事。psql它在 postgresql 仍在安装时移动到命令,即

[...]
Get:21 http://archive.ubuntu.com/ubuntu/ trusty/main ssl-cert all 1.0.33 [16.6 kB]
Get:22 http://archive.ubuntu.com/ubuntu/ trusty-updates/main postgresql-common all 154ubuntu1 [103 kB]
Get:23 http://archive.ubuntu.com/ubuntu/ trusty-updates/main postgresql-9.3 amd64 9.3.10-0ubuntu0.14.04 [2,669 kB]
Get:24 http://archive.ubuntu.com/ubuntu/ trusty-updates/main postgresql all 9.3+154ubuntu1 [5,038 B]
Fetched 5,834 kB in 28s (207 kB/s)                                             
Preconfiguring packages ...

    sudo -u postgres psql -c 'create database dvdrental;'
Selecting previously unselected package libroken18-heimdal:amd64.
(Reading database ... 14599 files and directories currently installed.)
Preparing to unpack .../libroken18-heimdal_1.6~git20131207+dfsg-1ubuntu1.1_amd64.deb ...
Unpacking libroken18-heimdal:amd64 (1.6~git20131207+dfsg-1ubuntu1.1) ...
Selecting previously unselected package libasn1-8-heimdal:amd64.
[...]

注意sudo -u postgres psql -c 'create database dvdrental;'输出中间的行的存在。有趣的是,它总是在 apt-get 命令的下载部分完成后立即显示...

有谁知道这可能是什么原因造成的?

bash
  • 1 1 个回答
  • 1411 Views

1 个回答

  • Voted
  1. Best Answer
    womble
    2015-11-30T20:43:21+08:002015-11-30T20:43:21+08:00

    哦,这是一个有趣的。

    简短的回答:它发生在那里是因为 apt(或它派生的东西)在其执行时正在读取标准输入,并且它读取脚本的其余行,因为那是当时仍在标准输入中的内容。简短的解决方法:放在行</dev/null尾apt-get install,然后继续您的一天。

    长答案(说真的,这是一个大枪):从正在运行的进程的角度来看,stdin/stdout/stderr 没有什么特别之处。它们只是文件描述符,当它们被分叉时,文件描述符在进程之间共享。所以,发生的事情(或多或少)是:

    1. 在终端中以交互方式运行的 bash 副本打开一个新的pipe(2),然后分叉一个新进程,该进程关闭现有的标准输出,然后使标准输出文件描述符 (1) 成为管道的写入端(参见dup2(2)) . 然后该子进程execscat sample.sh读取文件并将其写入它认为是标准输出的内容(但实际上是管道的写入端)。

    2. 在您的终端中以交互方式运行的 bash 副本分叉另一个新进程,这次关闭现有的stdin,然后使 stdin 文件描述符 (0) 成为前面讨论的同一管道的读取器端(再次调用dup2)。然后这个过程就是exec你的lxc-attach过程。

      如果在此过程中没有任何干扰标准输入(在这种特殊情况下不会),那么从将管道的读取器端作为标准输入的进程派生的每个进程也将具有完全相同的文件描述符,附加到与它的标准输入相同的管道,其中sample.sh填充了内容。 从该文件描述符读取的任何进程现在都将消耗读取的字节,并且从该文件描述符读取的任何其他进程都不会获得这些特定字节。请注意这一点;您将再次看到此材料。

    3. 当你的意大利马桶式管道盛会远端的 bash 终于开始时,它会从管道中读取“一些”数据,这是它的标准输入(因为这就是 bash 所做的,当没有参数和没有参数调用时)一个 tty 作为标准输入)。通过 的魔力strace,我刚刚确认 bash 实际上一次读取一个字符(而不是读取它,比如 4k 块),所以每个不属于 bash 的命令的单个字符,或当前正在执行,仍将位于管道中,其中-bash-has-as-its-stdin。

    4. 当 bash 执行脚本中的第二个命令apt-get installtra la la 时,它会派生一个新进程。它继承了 bash 的所有文件描述符,包括(最重要的是)我们的好朋友 pipe-which-is-stdin。这种情况也会发生在任何分叉的进程上apt-get(我向你保证,很多)。其中之一或apt-get它本身决定读取标准输入并将它读取的任何内容写入标准输出(或可能是标准错误)。

    5. 完成apt-get install后,bash 通过再次读取 stdin 来找出接下来要执行的操作。但是,因为其他东西已经从管道中读取了所有内容,所以什么都没有了,并且 bash 表示“哦,好吧,我想我已经完成了”并退出。再一次,管道是空的,因为其他东西已经读干了它,并且共享单个文件描述符的所有内容都共享了它的赏金。

    不出所料,“共享标准输入”问题的解决方案是停止在兄弟会聚会上像烟枪一样传递标准输入。由于您无法阻止fork(2) 自动为每个人提供相同的文件描述符,因此您需要告诉 bash 给apt-get(以及其他任何从该甜蜜、甜蜜的管道中非法啜饮的东西)其他东西来代替. 最容易给予的是/dev/null——永远忠实、永远不完整,你所有“戴夫不在这里,伙计”的快乐源泉。那是“输入重定向”的域,这就是它的</dev/null作用——它说,“嘿,bash,在你之前exec,apt-get用你从打开得到的文件描述符交换标准输入(文件描述符0)/dev/null”。

    供读者完成的练习:尝试</dev/zero在apt-get install命令之后放置,并解释为什么会发生这种情况。

    • 5

相关问题

  • Mac OS X:从 python 脚本中更改 $PATH

  • Bash 脚本:要求脚本以 root 身份运行(或使用 sudo)

  • crontab ifconfig 什么都不输出

  • 使用命令行工具按排序顺序计算重复项

  • 是否有 bash 等效于 ruby​​ 的“一些内容#{foo}”?

Sidebar

Stats

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

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

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

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve