Contents

命令替换

1. 概述

当我们有复杂的 shell 脚本时,我们经常需要在我们的逻辑中使用其他命令的输出。 在这个快速教程中,我们将看到如何使用命令替换来做到这一点。

2. 语法

我们先来看看语法。由于历史原因,我们可以使用两种语法

$(command) 
`command`

**推荐使用第一种形式,**因为它解决了不一致的行为。它也更具可读性。

我们应该记住,命令替换会产生一个sub-shell

让我们看一个简单的例子:

$ echo "Current path is ["$(pwd)"]"
Current path is [/home/blogdemo]

这也适用于旧语法:

$ echo "Current path is ["`pwd`"]"
Current path is [/home/blogdemo]

*在此示例中,*pwd 命令的输出替换了实际的 command

那么格式之间有什么区别呢?

让我们考虑这个例子:

$ function different_syntax() {
    echo "Backticks ["`echo \\blogdemo`"]"
    echo "Dollar ["$(echo \\blogdemo)"]"
}
$ different_syntax
Backticks [blogdemo]
Dollar [\blogdemo]

反斜杠以不同的方式处理反斜杠字符。具体来说,当它后面跟着*$ ` (反引号)或\*时,它的行为会有所不同。

考虑我们有一个变量指向一个存在的目录:

$ function different_syntax() {
    dir="/home"
    echo "Backticks ["`ls \$dir`"]"
    echo "Dollar ["$(ls \$dir)"]"
}
$ different_syntax
Backticks [blogdemo demo]
ls: cannot access '$dir': No such file or directory
Dollar []

在第一种情况下,反斜杠不会转义*$*字符,并且变量会扩展为它的值。

3. 引用和嵌套

现在我们已经了解了基本语法,让我们看看一些高级场景。

我们可以在命令替换表达式中使用嵌套

$ function nesting() {
    current_folders=$(ls $(pwd))
    echo "Current folders in $(pwd) ["$current_folders"]"
}
$ nesting
Current folders in /home [blogdemo demo]

首先,当前路径替换pwd命令。然后,我们将它传递给ls 并用它的输出替换整个表达式。最后,我们将输出存储在一个变量中。

当我们使用双引号时,Bash 不执行分词文件名扩展

$ function quoting() {
    for element in $(ls $(pwd))
        do 
            echo "["$element"]"
        done
}
$ quoting
[blogdemo]
[demo]

在这种情况下,我们遍历当前目录中的所有文件。

现在让我们看看如果我们在循环中使用引号会发生什么:

$ function quoting() {
    for element in "$(ls $(pwd))"
        do 
            echo "["$element"]"
        done
}
$ quoting
[blogdemo demo]

由于没有发生分词,我们迭代单个元素。 让我们以一个有用的片段结束:

$ ps -g $(ps -C firefox -o sid=)
  PID TTY          TIME CMD
 1652 ?        00:02:48 gnome-shell
 1815 ?        00:00:12 Xwayland
 2207 ?        00:00:09 ibus-daemon
 2214 ?        00:00:00 ibus-dconf
 2215 ?        00:00:02 ibus-extension-
 2217 ?        00:00:00 ibus-x11
 2232 ?        00:00:02 ibus-engine-sim
 2533 ?        00:09:36 firefox
 2670 ?        00:00:32 WebExtensions
...

让我们看看它的作用。首先,我们使用ps 命令搜索特定进程并打印其会话 ID。 我们在输出说明符之后使用*=*来抑制嵌套命令中的标题。

然后我们使用这个输出(会话 ID)来打印这个特定会话中的所有进程。