我需要了解以下 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
运作
使用管道时:
cmd2
是 的子进程cmd1
。- 的标准输入
cmd2
是“已堵塞”在 的标准输出上cmd1
。
由于 linux stdio lib 通过文件描述符提供缓冲流,因此 stdin 内容将被消耗(即只读一次)仅当标准输入打开时。
分步cmd1 | cmd2
工作流程
命令示例:
echo dir1 | (echo "a" ; read stdinvalue; echo "$stdinvalue")
echo dir1 |
:在第一个命令的标准输出上写入“dir1\n
”,该命令不会回显,而是通过标准输入输出缓冲,并可通过标准输入进行子进程。echo "a"
:在标准输出上写“a\n
”;不读取标准输入!所以“dir1\n
”字符串仍然可用read stdinvalue
:读取 stdin 直到 EOL(或 EOF)并将字符串存储在 bash 变量中echo "$stdinvalue"
:将 stdinvalue 变量值写入 stdout