Bash Shell 脚本/管道和替换
正如我们所见,一个命令的返回值,严格来说,只是一个小的非负整数,用于表示成功或失败。它真正的输出是它写入标准输出流的内容。默认情况下,写入标准输出流的文本会打印到终端,但有一些方法可以“捕获”它并用作命令的真实返回值。
当一系列命令在管道中链接在一起时,每个命令的输出都会作为输入传递给下一个命令。这是一种非常强大的技术,因为它允许我们将许多小的实用程序组合起来,创造出复杂的功能。
命令替换有点像变量扩展,但它运行一个命令并捕获它的输出,而不是简单地检索变量的值。例如,考虑我们上面的 `get_password` 示例。
#!/bin/bash
function get_password ( )
# Usage: get_password VARNAME
# Asks the user for a password; saves it as $VARNAME.
# Returns a non-zero exit status if standard input is not a terminal, or if the
# "read" command returns a non-zero exit status.
{
if [[ -t 0 ]] ; then
read -r -p 'Password:' -s "$1" && echo
else
return 1
fi
}
get_password PASSWORD && echo "$PASSWORD"
实际上,调用者没有必要将密码保存在变量中。如果 `get_password` 只将密码打印到它的标准输出,那么调用者可以使用命令替换,并直接使用它。
#!/bin/bash
function get_password ( )
# Usage: get_password
# Asks the user for a password; prints it for capture by calling code.
# Returns a non-zero exit status if standard input is not a terminal, or if
# standard output *is* a terminal, or if the "read" command returns a non-zero
# exit status.
{
if [[ -t 0 ]] && ! [[ -t 1 ]] ; then
local PASSWORD
read -r -p 'Password:' -s PASSWORD && echo >&2
echo "$PASSWORD"
else
return 1
fi
}
echo "$(get_password)"
为了评估 `"$(get_password)"`,Bash 在一个子 shell 中运行命令 `get_password`,捕获它的标准输出,并将 `"$(get_password)"` 替换为捕获的输出。
除了 `"$(…)"` 语法之外,还支持一种更古老的语法 `…`(使用反引号),并且仍然很常见。这两种语法具有相同的效果,但 `…` 的语法更严格,在复杂的情况下,它可能更难正确使用。
命令替换允许嵌套;类似于 `"$(b "$(c)")"` 的内容是允许的。(它运行命令 `c`,使用它的输出作为 `b` 的参数,并使用那个的输出作为 `a` 的参数)。
命令替换实际上可以包含一系列命令,而不仅仅是一个命令。正如我们之前所见,分号可以用作换行符来分隔命令,这在命令替换中很常见。每个用分号分隔的语句都在单个子 shell 中依次运行,并且它们的组合输出被捕获。命令替换还可以包含变量赋值和函数定义,但这些只有在替换内部有用,并且在替换完成后不会保留在父 shell 中。