Shell 中的特殊变量

ShellShellBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

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


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL shell(("Shell")) -.-> shell/BasicSyntaxandStructureGroup(["Basic Syntax and Structure"]) shell(("Shell")) -.-> shell/VariableHandlingGroup(["Variable Handling"]) linux(("Linux")) -.-> linux/BasicFileOperationsGroup(["Basic File Operations"]) shell(("Shell")) -.-> shell/ControlFlowGroup(["Control Flow"]) linux(("Linux")) -.-> linux/BasicSystemCommandsGroup(["Basic System Commands"]) shell(("Shell")) -.-> shell/FunctionsandScopeGroup(["Functions and Scope"]) linux/BasicSystemCommandsGroup -.-> linux/echo("Text Display") shell/BasicSyntaxandStructureGroup -.-> shell/shebang("Shebang") shell/BasicSyntaxandStructureGroup -.-> shell/comments("Comments") shell/VariableHandlingGroup -.-> shell/variables_usage("Variable Usage") linux/BasicFileOperationsGroup -.-> linux/touch("File Creating/Updating") linux/BasicFileOperationsGroup -.-> linux/chmod("Permission Modifying") shell/ControlFlowGroup -.-> shell/if_else("If-Else Statements") shell/ControlFlowGroup -.-> shell/for_loops("For Loops") shell/FunctionsandScopeGroup -.-> shell/func_def("Function Definition") subgraph Lab Skills linux/echo -.-> lab-388819{{"Shell 中的特殊变量"}} shell/shebang -.-> lab-388819{{"Shell 中的特殊变量"}} shell/comments -.-> lab-388819{{"Shell 中的特殊变量"}} shell/variables_usage -.-> lab-388819{{"Shell 中的特殊变量"}} linux/touch -.-> lab-388819{{"Shell 中的特殊变量"}} linux/chmod -.-> lab-388819{{"Shell 中的特殊变量"}} shell/if_else -.-> lab-388819{{"Shell 中的特殊变量"}} shell/for_loops -.-> lab-388819{{"Shell 中的特殊变量"}} shell/func_def -.-> lab-388819{{"Shell 中的特殊变量"}} end

创建你的第一个脚本

让我们从创建一个简单的 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。
  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: $!"

让我们分解这个脚本:

  • $? 提供最后执行的命令的退出状态。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(Internal Field Separator,内部字段分隔符)变量的第一个字符(通常是空格)分隔。

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

总结

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

关键要点:

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

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

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