Shell 中的特殊变量

ShellBeginner
立即练习

介绍

在本实验中,你将学习 Shell 脚本中的特殊变量。这些变量提供了关于脚本执行环境的关键信息,例如命令行参数、脚本名称和进程 ID。掌握这些变量将帮助你编写更加灵活且功能强大的 Shell 脚本。

这是一个引导实验,提供逐步指导以帮助你学习和练习。请仔细遵循说明完成每个步骤并获得实践经验。历史数据表明,这是一个初学者级别的实验,完成率为 99%。它获得了学习者 100% 的好评率。

创建你的第一个脚本

让我们从创建一个简单的 Shell 脚本开始,以此来演示特殊变量的使用。

  1. 在 WebIDE 中打开终端。你应该能看到一个等待输入的命令行提示符。

  2. 切换到项目目录:

cd ~/project

此命令将当前目录更改为 ~/project,这是你本实验的默认工作目录。

  1. 使用以下命令创建一个名为 special_vars.sh 的新文件:
touch special_vars.sh

touch 命令会在文件不存在时创建一个空文件,如果文件已存在则更新其时间戳。

  1. 在 WebIDE 编辑器中打开该文件。你可以通过点击屏幕左侧文件浏览器中的文件名来完成此操作。

  2. 将以下内容添加到文件中:

#!/bin/bash

echo "Script Name: $0"
echo "First Argument: $1"
echo "Second Argument: $2"
echo "All Arguments: $@"
echo "Number of Arguments: $#"
echo "Process ID: $$"

让我们逐行解析每一项的作用:

  • #!/bin/bash:这被称为 Shebang。它告诉系统使用 bash 来解释执行此脚本。
  • $0:这个特殊变量保存了脚本的名称。
  • $1$2:分别代表第一个和第二个命令行参数。
  • $@:代表传递给脚本的所有命令行参数。
  • $#:提供命令行参数的总数。
  • $$:提供当前 Shell 的进程 ID(PID)。
  1. 添加内容后保存文件。

  2. 在终端运行以下命令,为脚本添加执行权限:

chmod +x special_vars.sh

chmod 命令用于更改文件权限。+x 选项增加了执行权限,允许你运行该脚本。

运行带参数的脚本

现在我们已经创建了脚本,让我们带上不同的参数来运行它,看看特殊变量是如何表现的。

  1. 在不带任何参数的情况下运行脚本:
./special_vars.sh

脚本名称前的 ./ 告诉 Shell 在当前目录中查找该脚本。

你应该会看到类似这样的输出:

Script Name: ./special_vars.sh
First Argument:
Second Argument:
All Arguments:
Number of Arguments: 0
Process ID: 1234

请注意,由于我们没有提供任何参数,第一个和第二个参数为空,且参数个数为 0。

  1. 现在,带上一些参数运行脚本:
./special_vars.sh hello world

输出应该如下所示:

Script Name: ./special_vars.sh
First Argument: hello
Second Argument: world
All Arguments: hello world
Number of Arguments: 2
Process ID: 1235

以下是发生的变化:

  • $1 现在包含「hello」
  • $2 现在包含「world」
  • $@ 显示了所有参数:「hello world」
  • $# 显示为 2,因为我们提供了两个参数

进程 ID($$)在每次运行脚本时可能会有所不同,因为它是由操作系统动态分配的。

理解 $?$!

另外两个重要的特殊变量是 $?$!。让我们创建一个新脚本来演示它们的用法。

  1. 创建一个名为 exit_status.sh 的新文件:
touch ~/project/exit_status.sh
  1. 在 WebIDE 编辑器中打开该文件并添加以下内容:
#!/bin/bash

echo "Running a successful command:"
ls /home
echo "Exit status: $?"

echo "Running a command that will fail:"
ls /nonexistent_directory
echo "Exit status: $?"

echo "Running a background process:"
sleep 2 &
echo "Process ID of last background command: $!"

让我们解析一下这个脚本:

  • $? 提供上一个执行命令的退出状态(Exit Status)。0 通常表示成功,而非零值则表示各种错误情况。
  • $! 提供上一个后台命令的进程 ID。
  • 命令末尾的 & 符号使其在后台运行。
  1. 保存文件并添加执行权限:
chmod +x ~/project/exit_status.sh
  1. 运行脚本:
./exit_status.sh

你应该会看到类似这样的输出:

Running a successful command:
labex
Exit status: 0
Running a command that will fail:
ls: cannot access '/nonexistent_directory': No such file or directory
Exit status: 2
Running a background process:
Process ID of last background command: 1236

请注意:

  • 第一个 ls 命令执行成功,因此 $? 为 0。
  • 第二个 ls 命令失败(因为目录不存在),因此 $? 为 2(一个表示错误的非零值)。
  • sleep 命令在后台运行,$! 给出了它的进程 ID。

在函数中使用特殊变量

特殊变量也可以在函数内部使用。让我们创建一个脚本来演示这一点。

  1. 创建一个名为 function_vars.sh 的新文件:
touch ~/project/function_vars.sh
  1. 在 WebIDE 编辑器中打开该文件并添加以下内容:
#!/bin/bash

function print_args {
  echo "Function Name: $0"
  echo "First Argument: $1"
  echo "Second Argument: $2"
  echo "All Arguments: $@"
  echo "Number of Arguments: $#"
}

echo "Calling function with two arguments:"
print_args hello world

echo "Calling function with four arguments:"
print_args one two three four

这个脚本定义了一个使用特殊变量的函数 print_args。然后,它使用不同数量的参数两次调用该函数。

  1. 保存文件并添加执行权限:
chmod +x ~/project/function_vars.sh
  1. 运行脚本:
./function_vars.sh

你应该会看到类似这样的输出:

Calling function with two arguments:
Function Name: ./function_vars.sh
First Argument: hello
Second Argument: world
All Arguments: hello world
Number of Arguments: 2
Calling function with four arguments:
Function Name: ./function_vars.sh
First Argument: one
Second Argument: two
All Arguments: one two three four
Number of Arguments: 4

请注意:

  • $0 仍然指向脚本名称,而不是函数名称。
  • $1$2$@$# 在函数参数中的作用与在脚本参数中完全一致。
  • 每当使用不同参数调用函数时,这些变量的值都会随之改变。

理解 $@ 和 $* 的区别

特殊变量 $@$* 都用于表示所有命令行参数,但当它们被包含在双引号中时,行为会有所不同。让我们创建一个脚本来演示这种区别。

  1. 创建一个名为 at_vs_star.sh 的新文件:
touch ~/project/at_vs_star.sh
  1. 在 WebIDE 编辑器中打开该文件并添加以下内容:
#!/bin/bash

echo "Using \$@:"
for arg in "$@"; do
  echo "Argument: $arg"
done

echo "Using \$*:"
for arg in "$*"; do
  echo "Argument: $arg"
done

这个脚本演示了在循环中使用 "$@""$*" 的区别。

  1. 保存文件并添加执行权限:
chmod +x ~/project/at_vs_star.sh
  1. 运行脚本并传入多个参数,包括一些带有空格的参数:
./at_vs_star.sh "arg with spaces" another_arg "third arg"

你应该会看到类似这样的输出:

Using $@:
Argument: arg with spaces
Argument: another_arg
Argument: third arg
Using $*:
Argument: arg with spaces another_arg third arg

以下是发生的情况:

  • 使用 "$@" 时,每个参数都被视为一个独立的实体。带有空格的参数会被保留为单个单元。
  • 使用 "$*" 时,所有参数都被合并成一个单一的字符串,由 IFS(内部字段分隔符)变量的第一个字符(通常是空格)分隔。

当你需要处理可能包含空格或其他特殊字符的参数时,这种区别至关重要。

总结

在本实验中,你学习了 Shell 脚本中的特殊变量以及如何有效地使用它们。你创建了多个脚本来演示各种特殊变量的用法,例如 $0$1$@$#$$$?$!。你还探索了这些变量在不同上下文中的表现,包括在函数内部以及处理命令行参数时。

关键要点:

  1. $0$1$2 等代表脚本名称和命令行参数。
  2. $@$# 允许你处理所有参数并统计其数量。
  3. $$ 提供了当前进程 ID,这在创建唯一的临时文件时非常有用。
  4. $? 帮助你检查上一个命令是否执行成功。
  5. $! 提供了上一个后台进程的 PID,在作业控制中非常有用。
  6. "$@""$*" 在加引号时表现不同,这在处理带空格的参数时非常重要。

理解这些特殊变量对于编写更高级、更灵活的 Shell 脚本至关重要。它们允许你创建能够适应不同输入并提供执行环境重要信息的脚本。

随着你继续练习和尝试 Shell 脚本,你会发现更多在工作中使用这些特殊变量的方法。记得查阅 Bash 手册(man bash)以获取有关这些变量及其他特殊变量的更详细信息。