概述 Bash 的内部变量,以及在何处、如何和何时使用它们。
Section 36.1: Bash 内部变量概览
| Variable | Details |
|---|---|
$* / $@ |
函数/脚本位置参数(参数)。展开如下:$* 和 $@ 与 $1 $2 相同......(请注意,不加引号通常毫无意义) " $*" 与 "$1 $2 ..." 相同 " $@" 与 "$1" "$2" ... 相同1. 参数由 $IFS 的第一个字符分隔,该字符不一定是空格。 |
$# |
传递给脚本或函数的位置参数数 |
$! |
最近进入后台的作业中最后一个(对于管道而言为最右)命令的进程 ID(注意,启用作业控制时,它不一定与作业的进程组 ID 相同)。 |
$$ |
执行 bash 的进程的 ID |
$? |
最后一条命令的退出状态 |
$n |
位置参数,其中 n=1, 2, 3, ..., 9 |
${n} |
位置参数(同上),但 n 可以大于 9 |
$0 |
在脚本中,调用脚本的路径;用 bash -c 'printf “%s\n” “$0”' name args': name(内联脚本后的第一个参数),否则是 bash 收到的 argv[0] 。 |
$_ |
最后一条命令的最后一个字段 |
$IFS |
内部字段分离器 |
$PATH |
用于查找可执行文件的 PATH 环境变量 |
$OLDPWD |
上一个工作目录 |
$PWD |
当前工作目录 |
$FUNCNAME |
执行调用堆栈中的函数名数组 |
$BASH_SOURCE |
包含 FUNCNAME 数组中元素源路径的数组。可用于获取脚本路径。 |
$BASH_ALIASES |
包含当前定义的所有别名的关联数组 |
$BASH_REMATCH |
从最后一个 regex 匹配开始的匹配数组 |
$BASH_VERSION |
Bash 版本字符串 |
$BASH_VERSINFO |
由 6 个元素组成的数组,包含 Bash 版本信息 |
$BASH |
当前执行的 Bash shell 本身的绝对路径(由 bash 根据 argv[0] 和 $PATH 的值启发式确定;在某些情况下可能是错误的) |
$BASH_SUBSHELL |
Bash 子shell级别 |
$UID |
运行 bash 的进程的真实用户 ID(如果不同则无效)。 |
$PS1 |
主要命令行提示符;请参阅使用 PS* 变量 |
$PS2 |
二级命令行提示符(用于额外输入) |
$PS3 |
三级命令行提示(在选择循环中使用) |
$PS4 |
四级命令行提示(用于将信息添加到冗余输出中) |
$RANDOM |
一个介于 0 和 32767 之间的伪随机整数 |
$REPLY |
在未指定变量时,默认由 read 使用。SELECT 也会使用它来返回用户提供的值 |
$PIPESTATUS |
数组变量,用于保存最近执行的前台流水线中每条命令的退出状态值。 |
变量赋值前后不能有空格。例如
a=123和a = 123是不一样的,后者(用空格包围的等号)单独表示运行带有参数=和123的命令a,但它也出现在字符串比较运算符中(从语法上讲,它是[或[[或您使用的任何测试的参数)。
Section 36.2: $@
“$@"会将所有命令行参数扩展为单独的单词。它与“$*”不同,后者将所有参数扩展为一个单词。
“$@"在循环使用参数和处理带空格的参数时特别有用。
假设我们在一个脚本中调用了两个参数,就像这样
$ ./script.sh "␣1␣2␣" "␣3␣␣4␣"
变量 $* 或 $@ 将扩展为 $1␣$2,进而扩展为 1␣2␣3␣4,因此循环如下:
for var in $*; do # same for var in $@; do
echo \\<"$var"\\>
done
将同时打印
<1>
<2>
<3>
<4>
而“$*”将扩展为“$1␣$2”,进而扩展为“␣1␣2␣␣3␣␣4␣”,如此循环:
for var in "$*"; do
echo \\<"$var"\\>
done
只会调用 echo 一次,并打印
<␣1␣2␣␣␣3␣␣4␣>
最后,“$@”将扩展为“$1”“$2”,再扩展为“␣1␣2␣”“␣3␣␣4␣”,如此循环下去
for var in "$@"; do
echo \\<"$var"\\>
done
将打印
<␣1␣2␣>
<␣3␣␣4␣>
从而保留了参数的内部间距和参数分隔。需要注意的是,“for var in ”$@“; do ...”这种结构非常常见和习惯,它是 for 循环的默认结构,可以简写为 “for var; do ....”。
Section 36.3: $#
获取命令行参数或位置参数类型的数量:
#!/bin/bash
echo "$#"
当使用三个参数运行时,上面的示例将产生输出结果:
~> $ ./testscript.sh firstarg secondarg thirdarg
3
Section 36.4: $HISTSIZE
记录命令的最大数量:
~> $ echo $HISTSIZE
1000
Section 36.5: $FUNCNAME
要获取当前函数的名称,请输入
my_function()
{
echo "This function is $FUNCNAME" # This will output "This function is my_function"
}
如果在函数外输入该指令,则不会返回任何结果:
my_function
echo "This function is $FUNCNAME" # This will output "This function is"
Section 36.6: $HOME
用户的主目录
~> $ echo $HOME
/home/user
Section 36.7: $IFS
包含内部字段分隔符字符串,bash 在循环等情况下使用该字符串分割字符串。默认为空白字符: \n (换行符)、 \t(制表符)和空格。如果将其改为其他字符,则可以使用不同的字符来分割字符串:
IFS=","
INPUTSTR="a,b,c,d"
for field in ${INPUTSTR}; do
echo $field
done
输出结果如下
a
b
c
d
注释 这就是所谓的分词现象。
Section 36.8: $OLDPWD
OLDPWD(OLDPrintWorkingDirectory)包含最后一条 cd 命令之前的目录:
~> $ cd directory
directory> $ echo $OLDPWD
/home/user
Section 36.9: $PWD
PWD(PrintWorkingDirectory) 您当前所在的工作目录:
~> $ echo $PWD
/home/user
~> $ cd directory
directory> $ echo $PWD
/home/user/directory
Section 36.10: $1 $2 $3 etc..
从命令行或函数传递给脚本的位置参数:
#!/bin/bash
# $n is the n'th positional parameter
echo "$1"
echo "$2"
echo "$3"
输出结果如下
~> $ ./testscript.sh firstarg secondarg thirdarg
firstarg
secondarg
thirdarg
如果位置参数的个数大于 9,则必须使用大括号。
# "set -- " sets positional parameters
set -- 1 2 3 4 5 6 7 8 nine ten eleven twelve
# the following line will output 10 not 1 as the value of $1 the digit 1
# will be concatenated with the following 0
echo $10 # outputs 1
echo ${10} # outputs ten
# to show this clearly:
set -- arg{1..12}
echo $10
echo ${10}
Section 36.11: $*
将以一个字符串返回所有位置参数。
testscript.sh:
#!/bin/bash
echo "$*"
使用多个参数运行脚本:
./testscript.sh firstarg secondarg thirdarg
输出:
firstarg secondarg thirdarg
Section 36.12: $!
后台运行的最后一项任务的进程 ID (pid):
~> $ ls &
testfile1 testfile2
[1]+ Done ls
~> $ echo $!
21715
Section 36.13: $?
最后执行的函数或命令的退出状态。通常 0 表示 OK,否则表示失败:
~> $ ls *.blah;echo $?
ls: cannot access *.blah: No such file or directory
2
~> $ ls;echo $?
testfile1 testfile2
0
Section 36.14: $$
当前进程的进程 ID (pid):
~> $ echo $$
13246
Section 36.15: $RANDOM
每次引用该参数时,都会生成一个介于 0 和 32767 之间的随机整数。为该变量赋值可为随机数生成器(源)提供种子。
~> $ echo $RANDOM
27119
~> $ echo $RANDOM
1349
Section 36.16: $BASHPID
当前 Bash 实例的进程 ID (pid)。这与 $$ 变量不同,但结果往往相同。这是 Bash 4 的新功能,在 Bash 3 中不起作用。
~> $ echo "\$\$ pid = $$ BASHPID = $BASHPID"
$$ pid = 9265 BASHPID = 9265
Section 36.17: $BASH_ENV
指向 Bash 启动文件的环境变量,在调用脚本时读取。
Section 36.18: $BASH_VERSINFO
一个包含完整版本信息的数组,分为多个元素,如果只查找主要版本,比 $BASH_VERSION 更方便:
~> $ for ((i=0; i<=5; i++)); do echo "BASH_VERSINFO[$i] = ${BASH_VERSINFO[$i]}"; done
BASH_VERSINFO[0] = 3
BASH_VERSINFO[1] = 2
BASH_VERSINFO[2] = 25
BASH_VERSINFO[3] = 1
BASH_VERSINFO[4] = release
BASH_VERSINFO[5] = x86_64-redhat-linux-gnu
Section 36.19: $BASH_VERSION
显示正在运行的 bash 版本,以便决定是否可以使用任何高级功能:
~> $ echo $BASH_VERSION
4.1.2(1)-release
Section 36.20: $EDITOR
脚本或程序将使用的默认编辑器,通常是 vi 或 emacs。
~> $ echo $EDITOR
vi
Section 36.21: $HOSTNAME
启动时分配给系统的主机名。
~> $ echo $HOSTNAME
mybox.mydomain.com
Section 36.22: $HOSTTYPE
该变量用于识别硬件,有助于确定执行哪些二进制文件:
~> $ echo $HOSTTYPE
x86_64
Section 36.23: $MACHTYPE
与上面的 $HOSTTYPE 类似,它也包括操作系统和硬件的信息
~> $ echo $MACHTYPE
x86_64-redhat-linux-gnu
Section 36.24: $OSTYPE
返回机器上运行的操作系统类型的信息,例如
~> $ echo $OSTYPE
linux-gnu
Section 36.25: $PATH
查找命令二进制文件的搜索路径。常见的例子包括 /usr/bin 和 /usr/local/bin。
当用户或脚本尝试运行命令时,系统会搜索 $PATH 中的路径,以找到具有执行权限的匹配文件。
$PATH 中的目录用“: ”分隔。
~> $ echo "$PATH"
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin
例如,在上述 $PATH 的情况下,如果在提示符下输入 lss,shell 会依次查找 /usr/kerberos/bin/lss,然后是 /usr/local/bin/lss,然后是 /bin/lss,然后是 /usr/bin/lss,最后得出结论:没有这样的命令。
Section 36.26: $PPID
脚本或 shell 的父进程 ID (pid),即调用当前脚本或 shell 的进程。
~> $ echo $$
13016
~> $ echo $PPID
13015
Section 36.27: $SECONDS
脚本运行的秒数。如果在 shell 中显示,这个值可能会很大:
~> $ echo $SECONDS
98834
Section 36.28: $SHELLOPTS
bash 启动时提供的控制其行为的只读选项列表:
~> $ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
Section 36.29: $_
输出最后执行命令的最后一个字段,用于将某些信息传递给另一条命令:
~> $ ls *.sh;echo $_
testscript1.sh testscript2.sh
testscript2.sh
如果在其他命令之前使用,它会给出脚本路径:
test.sh:
#!/bin/bash
echo "$_"
Output:
~> $ ./test.sh # running test.sh
./test.sh
注意:这并不是获取脚本路径的万无一失的方法
Section 36.30: $GROUPS
一个数组,包含用户所在组的数量:
#!/usr/bin/env bash
echo You are assigned to the following groups:
for group in ${GROUPS[@]}; do
IFS=: read -r name dummy number members < <(getent group $group )
printf "name: %-10s number: %-15s members: %s\n" "$name" "$number" "$members"
done
Section 36.31: $LINENO
输出当前脚本的行号。主要用于调试脚本。
#!/bin/bash
# this is line 2
echo something # this is line 3
echo $LINENO # Will output 4
Section 36.32: $SHLVL
执行 bash 命令时,会打开一个新的 shell。环境变量 $SHLVL 保存了当前 shell 在其上运行的 shell 层数。
在新的终端窗口中,执行以下命令会根据所使用的 Linux 发行版产生不同的结果。
echo $SHLVL
使用 Fedora 25,输出结果为 “3”。这表明在打开一个新 shell 时,会执行一个初始 bash 命令并执行一项任务。初始 bash 命令会执行一个子进程(另一个 bash 命令),该子进程又会执行一个最终 bash 命令来打开新 shell。当新 shell 打开时,它是作为另外 2 个 shell 进程的子进程运行的,因此输出为 “3”。
在下面的示例中(鉴于用户运行的是 Fedora 25),新 shell 中 $SHLVL 的输出将设置为 “3”。
每执行一条 bash 命令,$SHLVL 就会递增一个。
~> $ echo $SHLVL
3
~> $ bash
~> $ echo $SHLVL
4
~> $ bash
~> $ echo $SHLVL
5
我们可以看到,执行 “bash ”命令(或执行 bash 脚本)会打开一个新的 shell。相比之下,源脚本运行的是当前 shell 中的代码。
test1.sh
#!/usr/bin/env bash
echo "Hello from test1.sh. My shell level is $SHLVL"
source "test2.sh"
test2.sh
#!/usr/bin/env bash
echo "Hello from test2.sh. My shell level is $SHLVL"
run.sh
#!/usr/bin/env bash
echo "Hello from run.sh. My shell level is $SHLVL"
./test1.sh
Execute:
chmod +x test1.sh && chmod +x run.sh
./run.sh
Output:
Hello from run.sh. My shell level is 4
Hello from test1.sh. My shell level is 5
Hello from test2.sh. My shell level is 5
Section 36.33: $UID
存储用户 ID 编号的只读变量:
~> $ echo $UID
12345