Contents

在bash脚本中模拟Enter键

1. 概述

在本教程中,我们将研究可用于绕过 shell 脚本和程序触发的确认提示的方法。我们将利用 Bash 中的现有命令来自动执行脚本。此外,我们将编写一个小的 Bash 脚本,我们将在整个教程中使用它。

2. 使用echo命令

简单的 echo 命令输出作为参数传递给它的字符串。当涉及到编写冗长的脚本时,它是 shell 脚本的圣杯,因为它无处不在。不仅如此,它还非常易于使用。

例如,让我们将一段文本打印到标准输出:

$ echo "I am being echoed"
I am being echoed

默认情况下,如果没有提供参数,它将打印一个隐式换行符

$ echo

我们可以利用它来模拟回车键:

$ echo | <command>

假设我们想使用Pacman 安装一个包,我们需要跳过确认消息。我们可以简单地将隐式换行符从echo传递给pacman命令:

# echo | pacman -S firefox

或者,我们可以使用echo命令更明确。命令中的-ne选项让echo*知道我们在文本中使用了换行符和转义符*:

# echo -ne '\n' | pacman -S firefox

2.1. 使用echo绕过提示

让我们创建一个场景,其中我们有一个包含我们需要安装的包列表的文本文件。我们会将这个批处理文件作为参数传递给脚本,然后脚本将安装这些包。

让我们创建一个名为pkgs.txt的文本文件,并将包名称放入其中:

mpv
ffmpeg
dunst
ranger
feh

接下来,我们将编写一个脚本,将文本文件作为参数并执行一些验证。之后,它将遍历文本文件的内容并使用pacman 包管理器从官方存储库安装包:

#!/bin/bash
# Check whether the file is provided
if [[ $# -eq 0 ]]; then
    echo 'Usage: ./install_packages.sh <file>'
    exit 0
fi
# Check whether the file exists
if [[ ! -f "$1" ]]; then
    echo "$1: No such file"
    exit 1
fi
pkgs=""
# Loop through the text file line by line
while IFS= read -r pkg; do
    # Append the package name to pkgs
    pkgs="$pkgs $pkg"
done < "$1"
# Install the packages
pacman -S $pkgs

现在,我们需要保存文件并执行它。请注意,我们需要 root 访问权限才能执行脚本

# ./install_packages.sh pkgs.txt
resolving dependencies...
looking for conflicting packages...
Packages (5) dunst-1.6.1-2 feh-3.7-1 ffmpeg-2:4.4-4 mpv-1:0.33.1-2 ranger-1.9.3-3
Total Installed Size: 41.39 MiB
Net Upgrade Size: 0.00 MiB
:: Proceed with installation? [Y/n]

如我们所见,它会提示确认安装软件包。我们将简单地使用echo命令来绕过它:

# echo | ./install_packages.sh pkgs.txt

现在,只要没有错误,脚本就会在没有烦人的确认提示的情况下执行。

3. yes命令

yes 命令向标准输出重复输出一个字符串,直到终止。它附带*coreutils *包,该包预装在大多数 Linux 发行版中。尽管它的功能简单,但对于不同的场景来说它是一个非常有用的实用程序。除了创建 CPU spike 之外,我们还可以使用它来自动化脚本。

让我们在没有任何参数的情况下在终端中尝试:

$ yes
y
y
y
y
y^C

我们可以通过按 CTRL + C 来终止进程。如果我们需要绕过 shell 脚本中的多个确认提示,它在场景中很有用。让我们稍微改变一下我们的脚本,让它一个一个地安装包,而不是作为一个整体安装它们:

#!/bin/bash
# Check whether the file is provided
if [[ $# -eq 0 ]]; then
    echo 'Usage: ./install_packages.sh <file>'
    exit 0
fi
# Check whether the file exists
if [[ ! -f "$1" ]]; then
    echo "$1: No such file"
    exit 1
fi
# Loop through the file line by line and install the packages
for pkg in $(cat $1); do
    pacman -S $pkg
done

该脚本现在将一个一个地同步安装包。但是,每次执行pacman命令时,我们都会收到确认提示。echo命令 仅对第一个提示有效,但是yes命令将响应多个提示。因此,我们将使用yes命令:

# yes | ./install_packages.sh pkgs.txt

该脚本现在可以顺利运行循环中的每个pacman命令,而不会在出现确认提示时停止。

4. expect效用

expect实用程序是一个旨在自动执行其他程序的程序。顾名思义,expect知道可以从另一个程序期望什么,以及对该程序做出什么响应。

4.1. 安装

可以使用包管理器从官方包存储库安装expect 程序。它在 expect包名下可用。安装后,使用以下命令确认:

$ expect -v
expect version 5.45.4

4.2. 用法

要使用expect程序,我们创建一个expect脚本,其中包含与程序交互所需的所有行为expect命令提供了几个操作:

  • spawn – 用于启动脚本
  • expect——等待程序输出
  • *send *——用于回复程序
  • *interact *——用于手动与程序交互

但是,编写一个长expect 脚本会浪费很多时间。幸运的是,expect带有autoexpect实用程序,我们将使用它自动为我们生成脚本:

# autoexpect ./install_packages.sh pkgs.txt

完成后,它将其输出写入script.exp文件。因此,下一次,当我们需要运行install_packages.sh脚本时,我们将使用script.exp文件生成它:

# ./script.exp

执行expect脚本后,我们可以观察到它使用script.exp模板自动响应我们的安装脚本。

5. 使用 Here Document 的解决方法

在 Bash 中,heredoc 或 here 文档是用作命令输入的部分。该部分被前面的命令视为单独的文件或输入流。例如,如果我们想在 Bash 脚本中为cat 命令提供一个文本流,我们可以使用这里的文档:

#!/bin/bash
cat <<END
Hello, World!
END

让我们分解这个例子:

  • cat命令将文本流从文件或标准输入打印到标准输出。
  • «END 关键字表示此处文档部分的开始。
  • 此部分中的内容被提供给cat命令。在我们的例子中,cat命令将打印 here 文档中的任何内容。
  • 最后的END关键字表示此处文档部分的结尾。

让我们将脚本保存到一个文件中并执行它:

$ ./heredoc.sh
Hello, World!

正如我们所见,它打印了 here document 部分中的文本。出于我们的目的,我们可以使用下面的heredoc来绕过确认提示。在提示我们确认的命令之后,我们将在此处文档部分简单地提供两个空行。

在我们的包安装脚本中,我们将简单地添加带有空行的此处文档部分:

for pkg in $(cat $1); do
    pacman -S $pkg <<END
END
done

一旦我们执行脚本,heredoc 就会像我们按两次 Enter 键一样工作。因此,提示将被自动确认。

6. 带有自动确认标志的程序

虽然我们可以在自定义 Bash 脚本中模拟 Enter 键,但有时有些程序会提供绕过确认提示的选项。例如,pacman命令使用*–noconfirm*标志:

$ sudo pacman -Sy --noconfirm doge

aptyum 包管理器也是如此。对于apt,有一个选项*–assume-yes*:

$ sudo apt install --assume-yes speedcrunch

同样,还有其他程序也可以选择在没有提示的情况下安静地执行。因此,最好在尝试上述部分中的方法之前检查此选项。