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 / 问题 / 425276
Accepted
mbigras
mbigras
Asked: 2018-02-20 13:06:26 +0800 CST2018-02-20 13:06:26 +0800 CST 2018-02-20 13:06:26 +0800 CST

使用 /dev/stdin 和 heredoc 从命令行传递文件

  • 772

我很好奇如何将 heredocs 作为文件传递给命令行实用程序的理论。

最近,我发现我可以将文件作为 heredoc 传递。

例如:

awk '{ split($0, arr, " "); print arr[2] }' <<EOF
foo bar baz
EOF
bar

这对我有利有几个原因:

  • Heredocs 提高了多行输入的可读性。
  • 我不需要记住每个实用程序标志来从命令行传递文件内容。
  • 我可以在给定文件中使用单引号和双引号。
  • 我可以控制外壳扩展。

例如:

ruby <<EOF
puts "'hello $HOME'"
EOF
'hello /Users/mbigras'

ruby <<'EOF'
puts "'hello $HOME'"
EOF
'hello $HOME'

我不清楚发生了什么。似乎shell认为heredoc是一个内容等于heredoc值的文件。我已经将这种技术与 cat 一起使用,但我仍然不确定发生了什么:

cat <<EOL
hello world
EOL
hello world

我知道cat打印文件的内容,所以大概这个heredoc是某种临时文件。

当我“将heredoc传递给命令行程序”时,我对到底发生了什么感到困惑。

这是一个使用ansible-playbook的示例。我将实用程序作为heredoc 传递给一个剧本;但是它失败了,如使用所示echo $?:

ansible-playbook -i localhost, -c local <<EOF &>/dev/null
---
- hosts: all
  gather_facts: false
  tasks:
    - name: Print something
      debug:
        msg: hello world
EOF
echo $?
5

但是,如果我将实用程序传递给相同的heredoc,但在它/dev/stdin之前成功

ansible-playbook -i localhost, -c local /dev/stdin <<EOF &>/dev/null
---
- hosts: all
  gather_facts: false
  tasks:
    - name: Print something
      debug:
        msg: hello world
EOF
echo $?
0
  • 当一个人“将heredoc作为文件传递”时到底发生了什么?
  • 为什么第一个版本ansible-playbook失败但第二个版本成功?
  • /dev/stdin在heredoc之前通过有什么意义?
  • 为什么其他实用程序喜欢ruby或awk不需要/dev/stdinheredoc之前的?
bash command-line
  • 3 3 个回答
  • 7356 Views

3 个回答

  • Voted
  1. Best Answer
    Michael Homer
    2018-02-20T13:21:02+08:002018-02-20T13:21:02+08:00

    当一个人“将heredoc作为文件传递”时到底发生了什么?

    你不是。Here-documents 提供标准输入,就像管道一样。你的例子

    awk '{ ... }' <<EOF
    foo bar baz
    EOF
    

    完全等同于

    echo foo bar baz | awk '{ ... }'
    

    awk, cat, 和ruby所有从标准输入读取的,如果它们没有在命令行上给出一个文件名来读取。那是一种实施选择。

    为什么使用 anisble-playbook 的第一个版本失败但第二个版本成功?

    ansible-playbook默认情况下不从标准输入读取,而是需要文件路径。这是一种设计选择。

    /dev/stdin很可能是指向的符号链接/dev/fd/0,这是谈论当前进程的文件描述符#0(标准输入)的一种方式。这是您的内核(或系统库)公开的东西。该ansible-playbook命令/dev/stdin像常规文件系统文件一样打开,并最终读取其自己的标准输入,否则会被忽略。

    您可能还拥有指向 FD 1/dev/stdout和/dev/stderr2 的链接,如果您要告诉某些东西将其输出放在哪里,您也可以使用它们。

    在heredoc之前传递/dev/stdin有什么意义?

    它是ansible-playbook命令的参数。

    为什么 ruby​​ 或 awk 等其他实用程序在 heredoc 之前不需要 /dev/stdin?

    默认情况下,它们从标准输入中读取作为设计选择,因为它们是为在管道中使用而设计的。他们出于同样的原因写入标准输出。

    • 10
  2. Kusalananda
    2018-02-20T13:15:21+08:002018-02-20T13:15:21+08:00

    here-document 是对命令标准输入的重定向,就像<. 这意味着在您可以<用来重定向文件内容的任何地方,您都可以重定向 here-document 的内容。POSIX 标准列出了 here-documents 以及其他重定向操作符。

    在您的 Ansible 示例中,ansible-playbook默认情况下不会从其标准输入流中读取,因为它需要文件名。通过将其/dev/stdin作为文件名,然后在标准输入中提供 here-document,您可以绕过实用程序中的此限制。“/dev/stdin文件”将始终包含当前进程的标准输入数据流。

    ruby以及awk许多其他实用程序将从标准输入中读取,除非在命令行上提供了文件名。

    因此,当您说“看起来 shell 认为 heredoc 是一个内容等于 heredoc 的值的文件”时,您在技术上是错误的。它不像文件(关于具有文件名和可搜索),而是作为标准输入上的数据流。至少从实用程序的角度来看。

    之间的区别是一样的

    cat file
    

    和

    cat <file
    

    在第一种情况下,cat打开文件file,但在第二种情况下(这也是 here-document 发生的情况),因为没有将文件名作为参数提供给cat,所以cat只读取其标准输入流(并且shell打开文件,或在实用程序的标准输入上提供此处文档)。该实用程序不需要知道所提供的数据是来自文件、管道、此处文档还是其他一些数据源。

    shell 如何实现 here-documents 在某种程度上并不重要,但它可能是通过使用 FIFO 或实际上是通过临时文件实现的。

    • 4
  3. Sergiy Kolodyazhnyy
    2018-02-20T13:40:50+08:002018-02-20T13:40:50+08:00

    here-docs 到底发生了什么取决于 shell 如何实现 here-doc:它可以在内部使用管道dash(如bash. 因此,在一种情况下,它可能是不可能的lseek(),但在另一种情况下 - 它可以(对于普通用户来说,这意味着您可以跳过 here-doc 的内容)。请参阅相关答案。

    至于两个 ansible-playbook 命令的情况,还取决于命令是如何实现的(所以除非您阅读源代码,否则您实际上不会知道)。有些命令只是检查是否提供了文件,不支持stdin. 其他命令,如awk和ruby- 它们旨在预期stdin或在命令行上指定的文件。

    但是,您可以尝试做的是,如果您使用的是 Linux,运行strace ansible-playbook ...<other args>并查看它尝试打开的内容、发生的系统调用等。例如,您会看到strace -e open tail /dev/stdin <<< "Jello World"tail 命令实际上会尝试打开/dev/stdin为文件,而trace -e open tail没有。

    • 4

相关问题

  • 没有服务器的命令行 pub/sub?

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

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