找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3960

积分

0

好友

522

主题
发表于 3 小时前 | 查看: 4| 回复: 0

36.1 变量赋值

在 Bash 中,变量赋值时等号两边千万不能有空格。正确的写法是 a=123,而不是 a = 123。如果将等号两边加上空格,Bash 会将其理解为执行命令 a,并将 =123 作为参数传递给它。当然,这种写法在字符串比较的语法中也会出现,但从本质上讲,它是 [[[ 这类测试命令的参数。

36.2 $@

$@ 会展开为所有命令行参数,并且每个参数都作为独立的单词处理。这一点和 $* 不同——$* 会将所有参数合并成一个单一的单词。

下面通过示例来说明。假设有一个脚本,用两个参数调用:

$ ./script.sh "1 2" "3 4"

此时 $* 将展开为 1 2 3 4,因此下面的循环:

for var in $*; do      # 等同于 for var in $@
    echo "<$var>"
done

将输出:

<1>
<2>
<3>
<4>

而如果使用 "$*",它会展开为 "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 ...

36.3 $

$# 用于获取命令行参数(或位置参数)的个数。示例脚本:

#!/bin/bash
echo $#

当用三个参数运行时,上述脚本将输出:

$ ./testscript.sh firstarg secondarg thirdarg
3

36.4 $HISTSIZE

HISTSIZE 变量记录了 Bash 历史中记住的命令最大数量。

$ echo $HISTSIZE
1000

36.5 $FUNCNAME

FUNCNAME 可以获取当前函数的名称。在函数内部:

my_function() {
    echo "This function is $FUNCNAME"   # 输出:This function is my_function
}

如果在函数外部使用,则返回空值:

echo "This function is $FUNCNAME"   # 输出:This function is

36.6 $HOME

HOME 是当前用户的主目录。

$ echo $HOME
/home/user

36.7 $IFS

IFS 包含了内部字段分隔符的字符串,Bash 在循环等操作中会用它来分割字符串。默认值是空白字符:换行 \n、制表符 \t 和空格。将其更改为其他字符,就可以用不同的字符来分割字符串:

IFS=","
INPUTSTR="a,b,c,d"
for field in $INPUTSTR; do
    echo $field
done

输出:

a
b
c
d

注意:这也就是所谓的“单词分割”。

36.8 $OLDPWD

OLDPWD 记录的是上一次执行 cd 命令之前的目录。

$ cd directory
directory> $ echo $OLDPWD
/home/user

36.9 $PWD

PWD 是当前所在的工作目录。

$ echo $PWD
/home/user
$ cd directory
directory> $ echo $PWD
/home/user/directory

36.10 $1、$2、$3 等

这些是传递给脚本或函数的位置参数,依次从命令行获取。

#!/bin/bash
# $n 是第 n 个位置参数
echo "$1"
echo "$2"
echo "$3"

运行示例:

$ ./testscript.sh firstarg secondarg thirdarg
firstarg
secondarg
thirdarg

如果位置参数的数量超过 9,必须使用花括号,比如 ${10}。例如:

set -- 1 2 3 4 5 6 7 8 nine ten eleven twelve
# 下面这行将输出 10(由 $1 的值 1 与后面的 0 拼接),而不是第10个参数
echo $10      # 实际被解析为 ${1}0,即 "10"
echo ${10}    # 正确输出:ten

更清晰的演示:

set -- arg{1..12}
echo $10      # 输出:arg10(${1}0 -> arg10)
echo ${10}    # 输出:arg10(第10个参数)

36.11 $*

$* 将所有位置参数作为一个单一的字符串返回。

testscript.sh

#!/bin/bash
echo "$*"

运行并传入多个参数:

./testscript.sh firstarg secondarg thirdarg

输出:

firstarg secondarg thirdarg

36.12 $!

$! 保存着最后一个放入后台执行的作业的进程 ID(PID)。

$ ls &
testfile1 testfile2
[1]+ Done    ls
$ echo $!
21715

36.13 $?

$? 是上一个执行的函数或命令的退出状态。通常 0 表示成功,其他非零值表示失败。

$ ls *.blah; echo $?
ls: cannot access *.blah: No such file or directory
2
$ ls; echo $?
testfile1 testfile2
0

36.14 $$

$$ 是当前进程的进程 ID(PID)。

$ echo $$
13246

36.15 $RANDOM

每次引用 $RANDOM 都会生成一个介于 0 和 32767 之间的随机整数。若对该变量赋值,则会为随机数生成器设定种子。

$ echo $RANDOM
27119
$ echo $RANDOM
1349

36.16 $BASHPID

BASHPID 是当前 Bash 实例的进程 ID。它与 $$ 变量有所不同,但在多数情况下结果相同。这是 Bash 4 新增的特性,在 Bash 3 中不可用。

$ echo "$$ pid = $$ BASHPID = $BASHPID"
$$ pid = 9265 BASHPID = 9265

36.17 $BASH_ENV

BASH_ENV 是一个环境变量,指向 Bash 的启动文件,该文件在脚本被调用时会被读取。

36.18 $BASH_VERSINFO

BASH_VERSINFO 是一个数组,包含了 Bash 的完整版本信息,拆分为多个元素。如果只需要主版本号,用它比用 $BASH_VERSION 方便得多。

$ for ((i=0; i<6; 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

36.19 $BASH_VERSION

BASH_VERSION 显示正在运行的 Bash 的版本,你可以据此决定是否能够使用某些高级特性。

$ echo $BASH_VERSION
4.1.2(1)-release

36.20 $EDITOR

EDITOR 是脚本或程序默认调用的编辑器,通常是 viemacs

$ echo $EDITOR
vi

36.21 $HOSTNAME

HOSTNAME 是系统启动时分配的主机名。

$ echo $HOSTNAME
mybox.mydomain.com

36.22 $HOSTTYPE

HOSTTYPE 用于标识硬件类型,可用来决定执行哪些二进制文件。

$ echo $HOSTTYPE
x86_64

36.23 $MACHTYPE

$HOSTTYPE 类似,MACHTYPE 还包含了操作系统信息以及硬件信息。

$ echo $MACHTYPE
x86_64-redhat-linux-gnu

36.24 $OSTYPE

OSTYPE 返回机器上运行的操作系统类型信息。

$ echo $OSTYPE
linux-gnu

36.25 $PATH

PATH 是用于查找命令二进制文件的搜索路径,常见目录包括 /usr/bin/usr/local/bin

当用户或脚本尝试运行一个命令时,Shell 会按顺序搜索 $PATH 中的路径,直到找到具有执行权限的匹配文件。

$PATH 中的目录由 : 字符分隔。

$ echo $PATH
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin

因此,给定上述 $PATH,如果在提示符下键入 ls,Shell 将依次查找 /usr/kerberos/bin/ls/usr/local/bin/ls/bin/ls/usr/bin/ls,最后才得出没有此命令的结论。

36.26 $PPID

PPID 是脚本或 Shell 的父进程的进程 ID,也就是调用当前脚本或 Shell 的那个进程。

$ echo $$
13016
$ echo $PPID
13015

36.27 $SECONDS

SECONDS 记录脚本已运行的秒数。如果在 Shell 中直接查看,这个数字通常比较大。

$ echo $SECONDS
98834

36.28 $SHELLOPTS

SHELLOPTS 是一个现成的列表,包含 Bash 启动时提供的用于控制其行为的选项。

$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

36.29 $_

$_ 会输出上一个执行的命令的最后一个字段,这对将内容传递给另一个命令十分有用。

$ ls *.sh; echo $_
testscript1.sh testscript2.sh
testscript2.sh

如果它在任何其他命令之前被使用,则会给出脚本的路径。但请注意,这并不是获取脚本路径的可靠方法。

# test.sh:
#!/bin/bash
echo $_

输出:

$ ./test.sh
./test.sh

36.30 $GROUPS

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

36.31 $LINENO

LINENO 输出当前脚本中的行号,主要用于调试脚本。

#!/bin/bash
# 这是第 2 行
echo something   # 这是第 3 行
echo $LINENO     # 将输出 4

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 的值就会增加 1。

$ echo $SHLVL
3
$ bash
$ echo $SHLVL
4
$ bash
$ echo $SHLVL
5

可以看到,直接执行 bash 命令(或运行一个 Bash 脚本)会打开一个新的 Shell。而 source 一个脚本则是在当前 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

赋予执行权限并运行:

$ chmod +x test1.sh test2.sh run.sh
$ ./run.sh

输出:

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

可见,test2.shsource 引入,所以它继承了 test1.sh 的 Shell 层级,而不是另开一个新的。

36.33 $UID

UID 是一个只读变量,存储用户的 ID 号。

$ echo $UID
12345

本文由云栈社区整理提供,更多 Bash 脚本编程与运维实战技巧,欢迎访问 云栈社区 Bash 专题




上一篇:从MinIO到OtterIO:如何将Apache 2.0旧代码线重构为可维护的新项目
下一篇:Python浮点数精度陷阱:为什么0.1+0.2不等于0.3及解决方案
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-6-8 23:16 , Processed in 0.869622 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表