如果我有这个 shell 脚本
str="A tremor in the Force.
The last time I felt it was in the presence of my old master."
cat <<< "$str"
Run Code Online (Sandbox Code Playgroud)
我的理解是命令
cat <<< "$str"
Run Code Online (Sandbox Code Playgroud)
告诉 shell 调用程序/bin/cat
并将参数传递给它$str
- 其中双引号$str
确保 shell 将传递未更改的参数。因此,如果cat
程序$str
未更改变量 - 那么它必须知道变量值吗?我的问题是,shell 是否将在其环境中声明的变量传递给它调用的其他系统程序?
shell 是否将在其环境中声明的变量传递给它调用的其他系统程序?
是的,但不是在 的情况下cat <<< "$str"
。
在类 Unix 操作系统中,大多数新程序的执行都是由于execve()
系统所有:
int execve(const char *filename, char *const argv[], char *const envp[]);
Run Code Online (Sandbox Code Playgroud)
shell 用于execv
执行程序,默认情况下,shell 将所有环境变量传递envp
到中,类似于传递命令行参数的方式argv
。从概念上讲,envp
是一个数组字符串,每个字符串的格式为NAME=value
。
man 2 execve
非常清楚地解释了整个过程,并包括工作示例代码。
在 的情况下cat <<<"$str"
,shell 将“$str”提供给cat
oncat
的标准输入,因此cat
永远不会看到名为 的变量str
,除非它先前由 shell 导出,例如通过调用export str
,但cat
无法知道这两个是有关的。
<<<
是一个“Here String”和一个shell扩展。从bash
手册页:
单词经历大括号扩展、波浪号扩展、参数和变量扩展、命令替换、算术扩展和引号删除。不执行路径名扩展和分词。结果作为单个字符串提供给其标准输入上的命令。
Here String 类似于传统的成语:
echo "$str" | cat
Run Code Online (Sandbox Code Playgroud)
我推荐。事实上,两者都会在标准输入的末尾添加一个换行符。我相信这两种方法是相同的,只要echo
不以任何方式修改输出(它可以取决于字符串的内容,因此更安全的版本是printf '%s' "$str"
而不是echo
)。
在您的情况下,我会使用printf '%s' "$str" | cat
它,因为它是最便携、通用且易于理解的,无需将您的脚本锁定为仅使用多个 shell 中的一个即可执行。如果您使用 POSIXsh
手册页作为您的 shell 脚本文档,您将需要掌握的材料较少,并且您学习的材料适用于所有 Bourne shell 衍生产品。
shell 调用的程序不继承 shell 变量。它们只继承环境变量。如果您编写export str
(或以一些不太常见的方式),则变量被放置在环境中,而不是仅分配给它。
cat
反正不会关心环境变量。
该命令cat <<< "$str"
不会将任何参数传递给cat
. 它cat
不带参数调用,但将标准输入连接到管道,shell 在该管道上写入变量的值str
和换行符。该cat
过程没有看到$str
,它看到了A tremor … my old master
(带有最后的换行符)。周围的双引号$str
可防止变量的值发生分词和通配符:"$str"
扩展到str
. 您可能会将双引号与单引号混淆——cat <<< '$str'
将$str
带有最后一个换行符的五字符字符串作为输入传递给cat
.