文章目录
shell中的变量
概述
Shell 变量是 Shell 编程中用于存储和引用数据的实体。它们可以是简单的文本字符串、数字,或者在某些情况下,甚至是更复杂的数据结构(尽管这通常依赖于特定的 Shell 和其扩展功能)。变量使得 Shell 脚本能够处理动态数据,增强脚本的灵活性和可重用性。
变量的作用
- 存储数据和字符串:Shell变量可以存储数字、文本字符串、文件名等各种类型的数据。这些数据可以是用户输入的信息、命令的输出结果,或者是脚本内部需要的临时数据。
- 传递参数:在Shell脚本中,可以通过特殊的变量来获取传递给脚本的参数。比如,$1、 2 、 2、 2、@等变量分别表示第一个参数、第二个参数和所有参数的列表。
- 控制程序流程:变量在控制程序流程中也起着重要作用。通过设置变量的值,可以控制脚本的分支和循环,实现条件判断和循环操作。
- 提高可读性和可维护性:使用变量可以使脚本更具可读性和可维护性。通过给数据和字符串起一个有意义的名字,可以使脚本更易于理解和修改。
- 避免重复输入:使用变量可以避免在脚本中重复输入相同的值或字符串,提高了代码的复用性和效率。
Shell 变量名与变量值
变量名
使用固定的名称,由系统预设或用户定义
- 规则:
- 不要使用系统的命令作为变量名
- 不要使用中文
- 不能特殊符号开头 可以用_来开头
- 在指定变量名的时候有一个默认的规则:计算机:computer 学生:student a= b=
- 要有注释,还要注意前后一致
- 只能包含字母、数字、下划线
- 严格区分大小写
变量值
能够根据用户设置、系统环境的变化而变化
- 字符串(String):
Shell脚本中的变量默认就是字符串。当你给变量赋值时,无论值是什么,它都被视为字符串。 - 整数(Int):
虽然变量本身是字符串,但你可以使用Shell的算术扩展($((expression))
)来进行整数运算。算术扩展允许你执行加、减、乘、除等整数运算。 - 布尔值(Boolean):
Shell没有原生的布尔类型,但你可以使用整数(0表示假,非0表示真)或字符串(空字符串表示假,非空字符串表示真)来模拟布尔值。在条件判断语句(如if
语句)中,你可以根据这些模拟的布尔值来决定是否执行某个代码块。 - 浮点数(Float)和双精度浮点数(Double):
Shell本身不直接支持浮点数运算。但是,你可以通过调用外部程序(如bc
、awk
、perl
、python
等)来处理浮点数和双精度浮点数。这些外部程序提供了更丰富的数学运算功能,包括浮点数运算。bc
是一个任意精度的计算器语言,它允许你设置小数点后的位数(即精度),并执行浮点数运算。awk
是一个强大的文本处理工具,它内置了对浮点数的支持,并提供了printf
函数来格式化输出浮点数。
变量的作用范围
在编程中,变量的作用范围(也称为变量的作用域)指的是变量在程序中可以被访问和修改的区域。根据变量的作用范围,变量可以被分为局部变量和全局变量两大类。
局部变量(Local Variables)
局部变量是在函数或代码块内部定义的变量。它们的作用范围仅限于定义它们的函数或代码块内部。一旦离开这个函数或代码块,局部变量就不再可用(即它们会被销毁)。这意味着局部变量只在定义它们的函数或代码块执行时存在,并且每个函数或代码块的局部变量都是独立的,互不影响。
特点:
- 只在定义它们的函数或代码块内部可见和可用。
- 函数或代码块执行完毕后,局部变量会被销毁。
- 不同的函数或代码块可以定义同名的局部变量,这些变量互不影响。
全局变量(Global Variables)
全局变量是在函数或代码块外部定义的变量。它们的作用范围是整个程序,即在整个程序中都可以访问和修改全局变量。全局变量在程序启动时被创建,在程序结束时被销毁。
特点:
- 在整个程序中都是可见的。
- 可以在程序的任何地方被访问和修改(但在某些编程语言中,可能需要特定的声明来在函数内部访问全局变量)。
- 如果多个函数或代码块需要共享数据,全局变量是一个选择,但过度使用全局变量可能会导致代码难以理解和维护。
注意
- 局部变量和全局变量的命名可以相同,但在同一个作用域内,局部变量的优先级高于全局变量。这意味着在函数内部,如果定义了与全局变量同名的局部变量,那么在该函数内部访问该变量时,会先访问局部变量。
- 为了避免命名冲突和提高代码的可读性,建议给局部变量和全局变量使用不同的命名规则或前缀。
- 在多线程编程中,全局变量的访问需要特别注意线程安全问题,因为多个线程可能会同时修改全局变量的值。
变量的类型
在Shell编程中,变量是存储信息的基本单位,它们可以根据其作用和来源分为环境变量、位置变量和预定义变量。
1. 环境变量(Environment Variables)
定义:环境变量是在操作系统中用来指定操作系统运行环境的一些参数。它们是在操作系统中一个具有特定名字的对象,包含了一个或多个应用程序所将使用到的信息。环境变量对系统内的所有用户进程都是可见的,可以被子进程继承。
常见环境变量:
PATH
:存储了所有命令所在的路径,当要求系统运行一个程序而没有给出其完整路径时,系统会在PATH
指定的路径中查找该程序。HOME
:用户登录时的主目录。USER
、UID
:当前用户的用户名和用户ID。HOSTNAME
:当前主机名。PWD
:当前工作目录的路径。PS1
:定义系统提示符的变量,用于显示命令行的提示符。LANG
:当前语言设置。
设置与查看:
- 在Unix/Linux系统中,可以使用
export
命令设置环境变量,如export PATH=$PATH:/new/path
。 - 使用
echo
命令结合$
符号查看环境变量的值,如echo $PATH
。
2. 位置变量(Positional Variables)
定义:位置变量主要是用来向脚本或程序中传递参数或数据的。它们在脚本或程序中被自动赋值,其名称和作用是固定的,不能自定义。
常见的位置变量:
$0
:表示当前执行的脚本或命令的名称(包括路径)。$1
到$9
:分别代表传递给脚本或命令的第一个到第九个参数。${10}
及以上:对于超过9个的参数,需要使用大括号{}
来明确变量的界限,如${10}
、${11}
等。$*
:表示传递给脚本的所有参数,但是将所有参数视为一个整体(即一个字符串)。当$*
被双引号("
)包围时,它会将所有的参数视为一个单一的字符串。$@
:也表示传递给脚本的所有参数,但是与$*
不同的是,$@
将每个参数视为独立的字符串。当$@
被双引号("
)包围时,它会保留每个参数作为独立的字符串。$#
:表示传递给脚本的参数的个数。
位置变量的使用示例:
假设有一个名为example.sh
的脚本,内容如下:
#!/bin/bash
echo "脚本名称: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "所有参数个数: $#"
echo "所有参数作为整体: $*"
echo "所有参数独立显示: $@"
执行该脚本并传递一些参数,如:
./example.sh arg1 arg2 arg3
输出将会是:
脚本名称: ./example.sh
第一个参数: arg1
第二个参数: arg2
所有参数个数: 3
所有参数作为整体: arg1 arg2 arg3
所有参数独立显示: arg1 arg2 arg3
注意:当$*
和$@
不加双引号时,它们在大多数情况下表现相似,但在被双引号包围时,它们的行为会有所不同。
进阶版使用:
- 处理超过9个的参数:使用
${10}
、${11}
等形式来访问超过9个的参数。 - 在循环中处理所有参数:可以使用for循环结合
$@
或$*
(但通常推荐使用$@
)来遍历所有参数。 - 参数扩展和修改:可以使用Shell的参数扩展功能来对位置变量的值进行修改或扩展。
注意:
- 在编写Shell脚本时,应该注意参数的数量和顺序,因为位置变量是根据它们在命令行中出现的顺序来命名的。
- 当处理不确定数量的参数时,应该使用
$#
来检查参数的个数,以避免潜在的错误。 - 在使用
$*
和$@
时,要注意它们在被双引号包围时的行为差异,并根据需要选择使用。
3. 预定义变量(Predefined Variables)
定义:预定义变量是Bash(或其他Shell)已经定义好的变量,它们的名称和作用都是固定的,用户不能修改其名称,但可以在脚本或命令行中引用它们的值。
常见预定义变量:
$0
:当前执行的脚本或命令的名称(包括路径)。在脚本中,它通常用于输出脚本自身的名称。$1
到$9
:位置参数,分别代表传递给脚本或命令的第一个到第九个参数。超过9个的参数可以通过${10}
、${11}
等方式访问。$*
和$@
:都代表传递给脚本的所有参数,但在双引号中引用时行为不同。$*
将所有参数视为一个整体(一个字符串),而$@
将每个参数视为独立的字符串。$#
:位置参数的数量,即传递给脚本的参数个数。$$
:当前Shell进程的PID(进程ID)。这是一个非常重要的变量,用于唯一标识当前运行的Shell进程。$!
:后台运行的最后一个进程的PID。这在你需要知道某个后台进程的ID以便稍后对其进行管理时非常有用。$?
:上一条命令的退出状态。如果命令成功执行,则$?
的值通常为0;如果命令执行失败,则$?
的值为非0值。这个变量在条件判断中非常有用。$-
:显示Shell使用的当前选项,这与set
命令的功能相同。它可以用来查看或修改Shell的行为选项。
使用:预定义变量为Shell编程提供了许多便利,它们允许脚本或命令获取关于当前环境或之前操作的信息。
补充:自定义变量
定义:
- 变量名:自定义变量的名称可以由字母、数字和下划线组成,但不能以数字开头。为了避免与系统命令或环境变量冲突,建议变量名具有一定的描述性和可读性。
- 赋值:定义变量时,使用等号(=)将变量名与变量值连接起来,注意等号两边不能有空格。如果变量值中包含空格、特殊字符(如*、?、$等),则需要用引号(单引号或双引号)将变量值括起来。
示例:
定义一个名为my_var
的自定义变量,并赋予它值"Hello, world!"
,可以这样做:
my_var="Hello, world!"
引用:
- 调用变量:在Shell中,要引用(或称为“展开”)自定义变量的值,需要在变量名前加上美元符号($)。例如,要打印上面定义的
my_var
变量的值,可以使用:
echo $my_var
或者,为了防止变量名与后面紧跟的字符混淆,可以使用花括号将变量名括起来:
echo ${my_var}
特性:
- 作用域:自定义变量默认只在定义它们的shell进程及其子进程中有效。一旦shell进程结束,这些变量也将不再存在。
- 修改和覆盖:可以通过重新赋值来修改自定义变量的值,新的值会覆盖旧的值。
- 只读变量:可以使用
readonly
命令将自定义变量设置为只读,之后就不能再修改这个变量的值了。
查看和取消:
- 查看变量:可以使用
set
命令(不带任何选项)来查看当前shell环境中定义的所有变量,包括自定义变量和环境变量。但更常用的是通过echo
或printenv
(针对环境变量)命令来查看特定变量的值。 - 取消变量:可以使用
unset
命令来取消(或称为“删除”)自定义变量,之后这个变量将不再存在,也不能再引用它的值了。
注意:
- 定义变量时,避免使用与系统命令或保留关键字相同的名称,以防止冲突。
- 在引用变量时,注意特殊字符和空格的处理,必要时使用引号。
- 自定义变量是Shell脚本编程中非常灵活和强大的工具,合理利用它们可以大大提高脚本的编写效率和可读性。
变量中的符号
在Shell脚本编程中,各种符号和引号扮演着重要的角色,它们定义了变量的处理方式、表达式的求值方式以及命令的执行方式。
基础符号
- 双引号 (" "): 双引号允许在字符串中引用变量(变量会被解析成其值),同时允许在字符串中包含转义字符(如
\n
表示换行)。但双引号内的变量名周围如果有空格,则空格也会被视为字符串的一部分。 - 单引号 (’ '): 单引号中的字符会原样输出,不会进行变量替换或命令替换。单引号内的所有字符都被视为字符串的组成部分,包括空格和特殊字符。
- 小括号 (( )): 在shell中,用于创建子shell,定义数组。在正则表达式中,用于捕获组,可以匹配并记住匹配的字串。
- 中括号 ([ ]): 用于条件测试和数组索引。在条件测试中,它用于比较数字或字符串是否满足某个条件(如
[ $a -eq $b ]
)。在数组索引中,用于指定数组中的元素(如${array[index]}
)。在正则表达式中,用于定义字符集,匹配中括号中的任意一个字符。 - 大括号 ({ }): shell中用于扩展字符串或者序列,也用于定义代码块。在正则表达式中不常用,用于扩展的正则表达语法中可能表示的数量范围。
- 双中括号 ([[ ]]): 在bash等shell中,用于更强大的条件测试,是更强大的引用。是一种比单中括号更强大的条件表达式,支持模式匹配等特性(如
[[ $a == z* ]]
)。 - 双小括号 (( )): 专门用于算术运算,支持算术比较,并且算术表达式中的变量可以自动转换为整数。双小括号是bash shell的扩展。
弱引用与强引用
在Shell脚本中,弱引用和强引用主要涉及变量的处理方式:
弱引用
- 定义:使用
${var}
或$var
的形式来引用变量。 - 特点:
- 允许变量扩展,即如果变量存在,它的值会被替换到引用处。
- 保留特殊字符的字面意义,特殊字符不会被Shell解释为命令或参数分隔符。
- 示例:
name="World" echo "Hello, $name!" # 输出: Hello, World!
强引用
- 定义:使用单引号
' '
来引用内容。 - 特点:
- 阻止任何变量扩展,变量名会被视为普通文本。
- 阻止特殊字符的解释,所有内容都被视为普通文本。
- 示例:
name="World" echo 'Hello, $name!' # 输出: Hello, $name!
总结来说,弱引用允许变量扩展和特殊字符的字面解释,而强引用则完全阻止这些行为,确保内容按原样输出。
变量的运算
数值运算
1. 使用expr
命令
expr
命令是一个用于执行整数算术运算的命令行工具。它也可以用于字符串操作和其他功能,但在这里我们只关注算术运算。
a=5
b=3
c=$(expr $a + $b)
echo $c # 输出 8
注意:expr
命令中的运算符(如+
、-
、*
、/
)和变量之间需要有空格。
2. 使用双小括号(( ))
双小括号(( ))
是Bash Shell的一个扩展,用于执行算术运算。它提供了比expr
更自然和灵活的语法。
a=5
b=3
((c = a + b))
echo $c # 输出 8
# 或者,更常见的是
((c = $a + $b))
echo $c # 输出 8
# 或者使用 $(( )) 来进行算术扩展
c=$((a + b))
echo $c # 输出 8
注意:在(( ))
中,变量名前的$
符号是可选的,但在使用$(( ))
进行算术扩展时,变量名前的$
是必须的。
3. 使用let
命令
let
命令也是Bash Shell中用于执行算术运算的命令。它的语法比较接近C
语言中的赋值语句。
a=5
b=3
let c=a+b
echo $c # 输出 8
# 或者使用 $ 符号
let c=$a+$b
echo $c # 输出 8
注意:在let
命令中,变量名前的$
符号是可选的,但加上它也不会出错。
4. 使用bc
命令
对于更复杂的算术运算(如浮点运算),可以使用bc
命令。bc
是一个任意精度的计算器语言。
a=5
b=3
c=$(echo "$a / $b" | bc)
echo $c # 输出 1.6666...(根据bc的配置,可能会有不同的精度)
# 对于浮点运算,可以设置bc的小数点后的位数:
c=$(echo "scale=2; $a / $b" | bc)
echo $c # 输出 1.67
#scale是一种特殊的变量可以用于指定小数位的精度:
scale=2
result=$(echo "scale=$scale;10/3" | bc )
echo=result
3.33
补充
在Shell脚本中,特别是Bash Shell,i++
、i--
、++i
这样的运算符通常不直接用在Shell脚本的算术表达式中,因为这些是C语言和其他一些编程语言中常见的自增(increment)和自减(decrement)运算符。然而,Bash Shell支持算术扩展,并且可以通过一些方式模拟这些运算符的行为。
在Bash中,没有直接的前缀(++i
)或后缀(i++
、i--
)自增自减运算符,但你可以通过算术扩展和赋值语句来实现相同的效果。
后缀自增和自减(i++
、i--
)
在Bash中,你可以通过先使用变量的值,然后再将其增加或减少来实现后缀自增自减的效果。但是,由于Bash的语法限制,你通常需要在两条语句中完成这个操作:
i=5
# 后缀自增
echo $i # 输出 5
((i++)) # 或者 let i=i+1
echo $i # 输出 6
# 后缀自减
((i--)) # 或者 let i=i-1
echo $i # 输出 5(如果之前i是6的话)
前缀自增(++i
)
前缀自增在Bash中可以通过在算术扩展中先增加变量的值,然后再使用它的值来实现:
i=5
# 前缀自增
((++i)) # 或者 let i=i+1,但这里主要是展示++i的效果
echo $i # 输出 6
条件运算
test
命令(也称为[ ]
)是Shell脚本中用于进行条件测试的命令。它用于检查某个条件是否成立,并根据结果返回一个退出状态码(exit status)。如果条件成立,test
命令返回0;如果条件不成立,返回非0值。
test
命令的语法:
test condition
或者使用方括号形式:
[ condition ]
常用的test
命令条件:
- 文件测试:
[ 操作符 文件/目录 ]-e
:文件存在-f
:普通文件存在-d
:目录存在-r
:文件可读-w
:文件可写-x
:文件可执行
- 字符串测试:
[ 字符串1 = 字符串2 ]或者[ 字符串1 == 字符串2 ]
[ 字符串1 != 字符串2]
=
或==
:字符串相等!=
:字符串不等-z
:字符串长度为0-n
:字符串长度不为0
[ -z "字符串" ]#检查是否为空(未定义或者赋空值的变量视为空串)
[ -n "字符串" ]#检查是否字符串存在
- 整数测试:
[ 整数变量1 操作符 整数变量2]
-eq
:整数相等-ne
:整数不等-gt
:整数大于-lt
:整数小于-ge
:整数大于等于-le
:整数小于等于
- 逻辑测试:
[ 表达式1 ] 操作符 [ 表达式2 ]
命令1 操作符 命令2
-a
或&&
:逻辑与-o
或||
:逻辑或-!
或!
:逻辑非
&&、|| 能正常存在于[[]]条件判断中,但[]中会报错:
a=5
[$a -ne 1] &&[ $a != 2] 等同于 [ $a -ne | -a $a != 2 ]
示例:
# 文件测试
if test -f "myfile.txt"; then
echo "File exists"
fi
# 字符串测试
name="World"
if [ "$name" = "World" ]; then
echo "Hello, World!"
fi
# 整数测试
a=5
b=3
if [ $a -eq $b ]; then
echo "a equals b"
else
入代码片
echo "a does not equal b"
fi
需要注意的是,在使用方括号[ ]
时,左右两边需要有空格,否则会被解释为文件名。例如,[ $a -eq $b ]
是正确的,而[$a -eq $b]
是不正确的。