关于 shell 脚本和管道的行为的澄清

关于 shell 脚本和管道的行为的澄清

我需要了解以下 shell 脚本的行为。

#!/bin/bash
echo "First more"
more $1

echo "First echo"
echo $1

echo "Second more"
more $1

当我运行以下命令时:

echo dir1 | bash script.sh

我得到以下输出

First more
dir1
First echo

Second more

为什么echo和 第二个more无法访问 的内容$1

当我运行以下命令时:

echo dir1 | bash script.sh dir2

我得到以下命令

First more

dir1

*** dir2: directory ***

First echo
dir2
Second more

*** dir2: directory ***

dir2被传递给所有命令,但更多只是打印dir1但被认为dir2是一个目录。

答案1

您混淆了参数和标准输入。将数据通过管道传输到程序并不等同于为其提供命令行参数。

在第一种情况下,您不向脚本传递任何参数,仅通过其标准输入流向其提供数据。因此$1在脚本的整个持续时间内都未设置。因此,
第一次调用more没有参数,并对标准输入进行分页。这将显示您通过管道输入的内容(dir1,作为文本)。后续的echo仅打印一个新行,因为它没有任何可打印的内容,而最后一个more也没有任何内容可打印 - 标准输入已被第一个输入“耗尽”。

在第二种情况下,您确实传递了一个参数。脚本中的$1价值也是如此。dir2同样的事情发生了,除了前more两个:

  • 通过两个标准输入进行分页
  • 尝试对文件进行分页dir2并出错,因为那是一个目录

echo 执行预期的操作,因为$1包含dir2, 以及最后more一个错误dir2- 它没有从标准输入读取任何内容。

答案2

区别在于“论点“VS”标准输入”。

当你跑步时echo dir1 | bash script.sh$1 争论你的script.sh总是空的,因为没有给它任何参数(尝试set -x在开头添加一个,你将在调试输出中看到它)。回响的内容dir1来自标准输入more如果没有给出参数,命令会读取 stdin(记住为$1空)。

如何cmd1 | cmd2运作

使用管道时:

  1. cmd2是 的子进程cmd1
  2. 的标准输入cmd2“已堵塞”在 的标准输出上cmd1

由于 linux stdio lib 通过文件描述符提供缓冲流,因此 stdin 内容将被消耗(即只读一次)仅当标准输入打开时

分步cmd1 | cmd2工作流程

命令示例:

echo dir1 | (echo "a" ; read stdinvalue; echo "$stdinvalue")

  1. echo dir1 |:在第一个命令的标准输出上写入“ dir1\n”,该命令不会回显,而是通过标准输入输出缓冲,并可通过标准输入进行子进程。
  2. echo "a":在标准输出上写“ a\n”;不读取标准输入!所以“ dir1\n”字符串仍然可用
  3. read stdinvalue:读取 stdin 直到 EOL(或 EOF)并将字符串存储在 bash 变量中
  4. echo "$stdinvalue":将 stdinvalue 变量值写入 stdout

相关内容