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