前军教程网

中小站长与DIV+CSS网页布局开发技术人员的首选CSS学习平台

解锁Linux:Shell变量_linux shell脚本变量赋值

引言:开启 Shell 编程大门

Shell 作为用户与 Linux 内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是批量处理文件、监控系统性能,还是自动化部署软件,Shell 编程都能轻松胜任。

一、Shell 是什么

(1)定义

Shell 是 Linux 系统中的命令行解释器,它就像是一个翻译官,位于用户和系统内核之间。用户通过在终端输入各种命令,这些命令被 Shell 接收并解析,然后 Shell 将其翻译成系统内核能够理解的指令,进而执行相应的操作,并将结果反馈给用户。

例如,当我们在终端输入 “ls” 命令时,Shell 会将这个命令传达给内核,内核执行后返回当前目录下的文件和目录信息,再由 Shell 展示给我们。

(2)常见 Shell 类型

在 Linux 世界里,有多种不同类型的 Shell,其中最常见的当属 bash 和 zsh 。

bash(Bourne-Again Shell)是大多数 Linux 发行版的默认 Shell,具有广泛的兼容性,几乎可以在所有的 Linux 系统上运行。它的语法简单,易于学习,对于初学者来说非常友好,丰富的内建命令和实用工具,能满足日常的各种基本操作需求,比如文件管理、进程控制等。同时,bash 还支持命令行历史记录和命令补全功能,让我们在操作时更加便捷高效。

zsh(Z Shell)则以其丰富的个性化配置和强大的功能而闻名。它拥有更智能的命令补全功能,不仅能补全命令,还能根据上下文自动补全参数、文件名等,甚至在我们拼写错误时,也能智能地给出提示和修正。此外,zsh 还支持各种主题和插件,通过安装不同的主题,我们可以让终端界面变得更加美观炫酷;借助插件,能进一步扩展其功能,如语法高亮、历史命令搜索、Git 快捷操作等,大大提升工作效率 。不过,zsh 的配置相对复杂一些,对于新手可能不太容易上手。

bash 是个很好的起点,它的稳定性和广泛适用性,能帮助你快速熟悉 Shell 编程的基本概念和操作。而当你对 Shell 有了一定的了解,想要追求更个性化、高效的操作体验时,zsh 则能满足你的进阶需求。

二、Shell 编程基础语法

在了解了 Shell 的基本概念后,接下来我们深入学习 Shell 编程的基础语法,这些语法是编写高效、灵活 Shell 脚本的基石。掌握好它们,你就能轻松驾驭 Shell 编程,实现各种复杂的自动化任务。

(1)脚本文件开头

在编写 Shell 脚本时,通常会在文件的第一行写下 “#!/bin/bash”,它的作用是指定该脚本使用的解释器为 Bash,也就是告诉系统,当执行这个脚本时,要调用 /bin/bash 程序来解释执行脚本中的命令。

这就好比我们打开一个文档时,需要指定用 Word、WPS 等相应的软件来打开一样,“#!/bin/bash” 就是在指明脚本的 “打开方式”。如果没有这一行,系统可能无法正确识别该如何执行脚本中的命令,导致脚本无法正常运行 。

(2)运行 Shell 脚本有几种方法

  1. 作为可执行程序:
chmod a+x myshell.sh
./myshell.sh

chmod a+x myshell.sh - 这条命令用于给 myshell.sh 脚本添加可执行权限

  • chmod 是改变文件权限的命令
  • a+x 表示给所有用户(所有者、组用户、其他用户)添加执行权限
  • myshell.sh 是目标脚本文件名

./myshell.sh - 这条命令用于执行当前目录下的 myshell.sh 脚本

  • ./ 表示当前目录
  • myshell.sh 是要执行的脚本文件名

执行这两条命令后,系统会运行你的 shell 脚本并执行其中包含的命令。如果脚本有输出内容,会显示在终端上。


. myshell.sh
source myshell.sh

. myshell.sh 是在当前 shell 环境中执行 myshell.sh 脚本的命令,也可以写成 source myshell.sh,两者效果完全相同。

这种执行方式与 ./myshell.sh 的主要区别在于:

  • . myshell.sh 会在当前 shell 进程中执行脚本,脚本中定义的变量、函数等会保留在当前 shell 环境中,执行完毕后可以直接使用
  • ./myshell.sh 会启动一个新的子 shell 进程来执行脚本,脚本中定义的变量等不会影响当前 shell 环境

通常在需要让脚本中的设置(如环境变量配置)生效到当前终端时,会使用这种方式,比如执行 .bashrc 或 .profile 等配置文件。


  1. 作为解释器参数
/bin/bash myshell.sh

/bin/bash myshell.sh 是指定使用 /bin/bash 解释器来执行 myshell.sh 脚本的命令。

这条命令的特点和用途:

  • 直接指定了脚本解释器为 /bin/bash,忽略脚本第一行的 #! 声明(即 shebang 行)
  • 即使脚本没有可执行权限(未执行 chmod +x),也能正常运行
  • 会启动一个新的 bash 子进程来执行脚本,脚本中定义的变量不会影响当前 shell 环境

这种方式常用于:

  • 临时指定特定版本的 bash 解释器执行脚本
  • 运行没有可执行权限的脚本
  • 脚本缺少正确的 shebang 声明时强制指定解释器

(3)编辑shell脚本文件并执行

打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell)

#!/bin/bash
echo "Hello World"

(4)变量

1.定义

Shell 变量无需声明数据类型(如整数、字符串),直接通过 “变量名=值” 的形式存储数据,本质是 “键值对”,用于在脚本中传递、复用信息(比如文件路径、配置参数、计算结果等)。在 Shell 中,变量的定义非常简单,不需要声明变量类型,直接赋值即可。

变量命名需要遵循一定的规则:

  • 只包含字母、数字和下划线: 变量名可以包含字母(大小写敏感)、数字和下划线 _,不能包含其他特殊字符。
  • 不能以数字开头: 变量名不能以数字开头,但可以包含数字。
  • 避免使用 Shell 关键字: 不要使用Shell的关键字(例如 if、then、else、fi、for、while 等)作为变量名,以免引起混淆。
  • 使用大写字母表示常量: 习惯上,常量的变量名通常使用大写字母,例如 PI=3.14。
  • 避免使用特殊符号: 尽量避免在变量名中使用特殊符号,因为它们可能与 Shell 的语法产生冲突。
  • 避免使用空格: 变量名中不应该包含空格,因为空格通常用于分隔命令和参数。

这里要注意,变量名和等号之间不能有空格

# 存储字符串
name="张三"
# 存储整数
age=20
# 存储路径
log_path="/var/log/syslog"


特殊变量:

除了我们自定义的变量,Shell 中还有一些特殊变量,它们有着特殊的用途。比如 “0”,它用于获取当前脚本的名称。假设我们有一个名为test.sh的脚本,在脚本中使用echo 0,就会输出 “test.sh”,这在需要根据脚本名进行不同操作的场景中非常有用 。“1”“2”…… 则用于获取脚本执行时传入的参数,“1”表示第一个参数,“2” 表示第二个参数,以此类推。例如,我们执行脚本 “./test.sh arg1 arg2”,在脚本中使用 echo 1,就会输出“arg1”,使用echo 2 会输出 “arg2” 。这些特殊变量在处理命令行参数、实现脚本的灵活性方面发挥着重要作用。

2.变量的使用:$变量名 或 ${变量名}

调用变量时,在变量名前加$;若变量名后紧跟其他字符(如字母、数字),需用${}包裹避免歧义。

# 定义变量
user="Alice"
score=95
# 基本使用:$变量名
echo "用户名:$user" # 输出:用户名:Alice
# 避免歧义:${变量名}
echo "用户分数:${score}分" # 输出:用户分数:95分
(若写$score分,会被识别为“$score分”变量,导致错误)

3.只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

#! /bin/bash
url="www.baidu.com"
readonly url
url="www.google.com"

运行结果:

[toto@centos shell]$ bash test.sh
test.sh:行4: url: 只读变量

4.变量的修改与删除

修改:直接重新赋值(覆盖旧值):

name="Bob"
name="Charlie" # 新值覆盖旧值,最终name为"Charlie"

删除:用unset 变量名删除变量(删除后变量不可用):

unset name # 删除name变量
echo $name # 输出空(变量已不存在)

示例:

#!/bin/sh
Url="https://www.baidu.com"
unset Url
echo $Url

运行结果为空

5.变量赋值:从命令结果获取值(命令替换)

用$(命令)或反引号`命令`,将命令的输出结果赋值给变量(推荐$(命令),兼容性更好)。

示例:

# 获取当前日期(格式:年-月-日)
today=$(date +%Y-%m-%d)
echo "今天日期:$today" # 输出:今天日期:2024-05-20
# 获取当前目录下的文件数
file_count=$(ls | wc -l)
echo "当前目录文件数:$file_count"

6.变量运算:整数计算(无需额外工具)

用$((表达式))直接对变量进行算术运算(支持+ - * / %等运算符)。

示例:

a=10
b=3
# 加法
sum=$((a + b))
# 乘法
product=$((a * b))
# 取余
remainder=$((a % b))
echo "sum: $sum, product: $product, remainder: $remainder"
# 输出:sum: 13, product: 30, remainder: 1

7.变量类型

字符串变量

在 Shell 中,字符串变量是最为常见的一种类型。定义字符串变量时,既可以使用单引号,也可以使用双引号 。比如:

# 使用单引号定义字符串变量
single_quote_str='这是一个使用单引号定义的字符串'
# 使用双引号定义字符串变量
double_quote_str="这是一个使用双引号定义的字符串"

单引号和双引号在定义字符串变量时有着明显的区别。单引号中的内容会被原样输出,其中的变量不会被解析。例如:

name="张三"
single_quote_greeting='你好,$name'
echo $single_quote_greeting

上述代码的输出结果是你好,$name,可以看到,单引号中的$name并没有被替换成实际的变量值。

而双引号则不同,双引号中的变量会被解析成实际的值,还能识别转义字符。例如:

name="李四"
double_quote_greeting="你好,$name\n欢迎来到这里!"
echo -e $double_quote_greeting

这里的-e选项是为了让echo命令识别转义字符,输出结果会是:

你好,李四
欢迎来到这里!

1. 快速获取字符串长度

使用${#字符串名}即可直接返回字符串长度,若将字符串视为单元素数组,${#字符串名[0]}结果完全一致。

# 实例:计算字符串长度
string="abcd"
echo ${#string} # 输出 4(直接获取长度)
echo ${#string[0]} # 输出 4(数组形式获取,结果相同)

2. 精准提取子字符串

语法格式为${字符串名:起始索引:截取长度},注意:第一个字符的索引为 0,若省略 “截取长度”,则默认截取到字符串末尾。

# 实例1:从第2个字符开始,截取4个字符
string="runoob is a great site"
echo ${string:1:4} # 输出 unoo(索引1对应第2个字符"u",截取4位)
# 实例2:从第6个字符截取到末尾
echo ${string:5} # 输出 ob is a great site(索引5对应"o",省略长度则取剩余所有字符)

3. 查找子字符串位置

借助expr index "$字符串名" 目标字符集,可获取字符集中首个出现字符的位置(从 1 开始计数),若未找到则返回 0。

# 实例:查找"i"或"o"的首次出现位置
string="runoob is a great site"
echo `expr index "$string" io` # 输出 4("o"在第4位,比"i"先出现)

注意:此处使用的是反引号 `(键盘左上角,与~同键),而非单引号 ',用于执行 expr 命令并返回结果。

整数变量

在某些 Shell 中,可以使用declare或typeset命令来声明整数变量。一旦声明为整数变量,它就只能存储整数值。例如:

# 使用declare声明整数变量
declare -i num=10

当给整数变量赋非整数值时,Shell 会尝试将其转换为整数。比如:

declare -i num='10.5'
echo $num
上述代码的输出结果是10,可以看出,10.5被转换为了整数10。

数组变量

Shell 支持数组变量,它允许在一个变量中存储多个值,包括整数索引数组和关联数组。

整数索引数组的定义方式如下:

# 定义整数索引数组
int_array=(1 2 3 4 5)

通过索引可以访问数组中的元素,索引从 0 开始。例如,要访问数组中的第三个元素,可以这样做:

echo ${int_array[2]}

关联数组则使用键值对的方式存储数据,定义时需要先声明为关联数组类型。例如:

# 声明关联数组
declare -A assoc_array
# 给关联数组赋值
assoc_array["name"]="王五"
assoc_array["age"]=25

访问关联数组的元素时,使用键来获取对应的值:

echo ${assoc_array["name"]}
echo ${assoc_array["age"]}

环境变量

环境变量是由操作系统或用户设置的特殊变量,对 Shell 的行为和执行环境有着重要影响。常见的环境变量有PATH、HOME、LANG等。

PATH变量包含了操作系统搜索可执行文件的路径。当我们在命令行输入一个命令时,系统会按照PATH变量中列出的路径依次查找对应的可执行文件。例如:

echo $PATH

HOME变量表示当前用户的主目录路径。比如,在 Linux 系统中,普通用户的主目录通常是/home/用户名,通过HOME变量就可以方便地获取这个路径。

LANG变量则用于设置系统的语言环境,影响着系统中各种信息的显示语言。

特殊变量

在 Shell 中,还有一些特殊变量,它们有着特定的含义和用途。

$0表示脚本的名称。比如有一个名为test.sh的脚本,在脚本内部使用$0,就会得到test.sh。

$1、$2等表示脚本的参数。假设我们有一个脚本arg_test.sh,执行时传入两个参数:

./arg_test.sh param1 param2

在脚本内部,$1就代表param1,$2就代表param2。

$#表示传递给脚本的参数数量。继续以上面的例子来说,$#的值就是2。

$?表示上一个命令的退出状态,正常退出时返回值为 0,非 0 则表示命令执行过程中出现了错误。例如,执行一个不存在的命令:

nonexistent_command
echo $?

这里的输出结果就会是一个非 0 的值,具体数值根据系统而定,通常表示命令未找到的错误状态 。

(5)Shell 数组:一维数组的灵活运用

Bash 仅支持一维数组,无大小限制,下标从 0 开始,可灵活定义和访问元素,适合存储批量数据。

1. 三种数组定义方式

数组元素用空格分隔,支持集中定义、分行定义和单独赋值,甚至可使用非连续下标。

# 方式1:集中定义(最常用)
array_name=(value0 value1 value2 value3)

# 方式2:分行定义(适合元素较多的场景)
array_name=(
value0
value1
value2
value3
)

# 方式3:单独赋值(支持非连续下标)
array_name[0]=value0
array_name[2]=value2 # 跳过下标1,直接定义下标2
array_name[5]=value5 # 下标范围无限制,无需连续

2. 数组元素的读取与遍历

读取单个元素:${数组名[下标]}
获取所有元素实现遍历:${数组名[@]}或${数组名[*]}
# 实例:定义并读取数组
array_name=(apple banana cherry date)

# 读取单个元素(下标2对应第3个元素)
echo ${array_name[2]} # 输出 cherry

# 读取所有元素(两种方式等价)
echo ${array_name[@]} # 输出 apple banana cherry date
echo ${array_name[*]} # 输出 apple banana cherry date

# 遍历数组(推荐用@,可正确处理含空格的元素)
for fruit in ${array_name[@]}; do
			echo "水果:$fruit"
done

3. 获取数组长度

获取数组元素总数:${#数组名[@]}或${#数组名[*]}
计算某元素的长度:${#数组名[下标]}
# 实例:计算数组及元素长度
array_name=(apple banana cherry)

# 数组元素总数
length=${#array_name[@]}
echo "数组长度:$length" # 输出 3

# 单个元素长度(下标1对应"banana")
elem_length=${#array_name[1]}
echo "元素长度:$elem_length" # 输出 

三、Shell 注释:让脚本更易读

注释是脚本的 “说明书”,合理使用注释能提升代码可维护性,避免后期 “看不懂自己写的代码”。

1. 单行注释:用 #标注

以#开头的行均为注释,会被 Shell 解释器忽略,适合简短说明。

# 这是单行注释,用于解释下一行代码的功能
string="hello world" # 定义字符串(行尾注释,补充代码作用)
echo $string # 输出字符串内容

2. 多行注释:三种实用方式

当需要注释大段代码时,无需逐行加#,以下三种方式可快速实现多行注释。

方式 1:Here 文档(推荐)

用:<<标识符和标识符包裹注释内容,标识符可自定义(如 EOF、COMMENT、! 等),建议使用大写字母区分。

# 实例1:用EOF作为标识符
:<<EOF
这是多行注释的第一行
第二行注释内容,可写脚本说明、作者信息等
第三行:本脚本用于处理日志文件
EOF

# 实例2:用!作为标识符
:<<!
注释内容...
支持任意行数
!

方式 2:空函数包裹

将注释内容定义为无调用的函数,函数内代码不会执行,间接实现注释效果。

# 实例:用空函数注释大段代码
comment() {
		这是通过函数实现的多行注释
		适合临时注释大段代码,后续取消注释只需调用函数即可
		echo "这段代码不会执行"
}

方式 3:冒号 + 单引号

:是 Shell 的空命令(执行后无任何操作),配合单引号包裹多行内容,简单高效。

# 实例:冒号+单引号实现多行注释

: '
这是注释内容
无需定义标识符,直接用单引号包裹
适合快速临时注释
'

四、总结

Shell 编程不仅是系统管理员必备的技能,对于开发人员、数据分析师等也有着重要的意义 它能帮助我们自动化繁琐的任务,提高工作效率,让我们有更多的时间和精力去专注于更有价值的工作 。

学习 Shell 编程是一个持续的过程,希望大家在今后的学习和工作中,能够不断地实践和探索,将所学知识运用到实际项目中 。你可以尝试编写更复杂的脚本,探索自动化运维、服务器管理、数据处理等更多的应用场景 。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言