Bash 编程语法

Bash 简介

Bash 是 Bourne Shell 程序 "sh" 的升级版本,是一个开源 GNU 项目。Bash 是一个命令处理器,通常运行于文本窗口中,可以将用户输入的命令解释并执行相应的操作,这样的文件被称作脚本。

Bash 是绝大多数 Linux、MAC 及 OS 默认的 shell 程序。

Bash 特点

  • Bash 与 sh 兼容,并具有 Korn Shell 和 C Shell 的最佳功能特性。
  • Bash 中的每个文件都有其特定用途,这些文件的集合用于创建环境。
  • Bash 可以通过键位绑定设置自定义的编辑键序列。
  • Bash 包含了一维数组,它们可以帮助您轻松的引用和操作数据列表。
  • Bash 中的目录堆栈指定了列表中最近访问的目录历史记录。操作示例: - pushed 用于将目录添加至堆栈中;popd 用于将目录从堆栈中删除;dirs 用于显示堆栈中的内容。
  • Bash 包含用于环境安全的受限模式。

Bash 变量

变量的定义

在 Bash 中,变量的定义非常简单,只需要将变量名和值用=连接即可。

语法:

cpp 复制代码
Variable_name=value

Bash 变量的定义使用规则

  • 变量名区分大小写,a和A为两个不同的变量。
  • 变量名可以使用大小写字母混编的形式进行编写。
  • 变量名与值之前的 = 两侧都不能有空格。
  • 在读取或打印变量时,需使用$加变量名。
  • 变量可以写在 Bash 脚本中的任何地方,在运行时,Bash 会自动将其替换为变量值。
    示例:
cpp 复制代码
name="Tom"
echo $name
结果:
Tom

数据类型

在 Bash 中声明变量后赋值,它会自动判断数据类型,不必在声明的同时去定义变量的数据类型。

变量的类型

  • 系统定义的变量:通常是以大写字母形式存在,如 BASH、SHELL 等。
  • 用户定义的变量:多数以小写字母参与命名,但不具有大小写强制性规定。
cpp 复制代码
示例:
name="abc"
echo $name
echo $BASH
结果:
abc
/usr/bin/bash

只读变量

使用 readonly 命令可以将变量设置为只读,无法修改其值。

cpp 复制代码
示例:
a="123"
readonly a
a="456"  #此操作将失败

echo $a
结果:
line 3: a: readonly variable
123
变量 a 被设置为只读,尝试修改其值会导致错误。

删除变量

使用unset命令可以删除变量。

示例:

cpp 复制代码
variable_name="some_value"
unset variable_name
echo $variable_name  # 不会输出任何内容
  • 变量variable_name 被删除后,使用 $variable_name 读取其值将不会输出任何内容。

字符串的拼接

cpp 复制代码
示例:
str1="Hello"
str2="World"
str3="${str1} ${str2}"
echo $str3
结果:
Hello World
使用 ${str1} 和 ${str2} 进行字符串拼接,结果赋值给 str3。

Bash 引号

在 Bash 中,可以使用单引号和双引号来处理字符串,使用不同的引号方式会对字符串解析产生不同的效果。

单引号和双引号的区别

  • 单引号 '':将字符串内的所有内容原样输出,不进行变量替换或命令替换。
  • 双引号 "":允许对字符串内的变量和命令进行替换。
cpp 复制代码
示例:
name="Tom"
echo "Hello, $name"   # 使用双引号可以解析变量
echo 'Hello, $name'   # 使用单引号不会解析变量
结果:
Hello, Tom
Hello, $name
使用双引号时,变量$name被解析为值Tom,而使用单引号时,变量名$name被原样输出。

Bash 数组

数组可以定义为相似类型元素的集合,在 Bash 中数组不必是相似类型元素的集合。

索引数据的声明和赋值

cpp 复制代码
示例:
通过 declare -a 声明一个索引数组,并通过键赋值。
declare -A Array_Name
Array_Name["name1"]="value_1"
Array_Name["name2"]="value_2"
# 或
Array_Name=(
    ["name1"]="value_1"
    ["name2"]="value_2"
)

关联数组的声明和赋值

使用 declare -A 声明一个关联数组,并通过键赋值。

cpp 复制代码
示例:
declare -A Array_Name
Array_Name["name1"]="value_1"
Array_Name["name2"]="value_2"
# 或
Array_Name=(
    ["name1"]="value_1"
    ["name2"]="value_2"
)

数组的访问

使用数组的索引或键来访问数组中的元素。

cpp 复制代码
示例:
declare -a arr1=("hello" "world")
declare -A arr2=(["key1"]="hello" ["key2"]="world")
echo ${arr1[1]}
echo ${arr2["key1"]}
结果:
world
hello

取出所有元素

{arr\[@\]} 和 {arr[*]} 都可以取出数组中的所有元素。

cpp 复制代码
示例:
declare -a arr1=("hello" "world")
echo ${arr1[@]}
echo ${arr1[*]}
结果:
hello world
hello world

向数组中添加元素

使用 += 运算符或指定索引来向数组中添加元素。

cpp 复制代码
示例:
declare -a arr=("hello" "world")
arr+=("Tom")
arr[5]="harry"
echo ${arr[*]}
结果:
hello world Tom harry

输出索引

${!arr[@]} 返回数组中所有元素的索引。

cpp 复制代码
示例:
declare -a arr=("hello" "world")
arr+=("hogwarts")
arr[5]="harry"
echo "arr indexes are ${!arr[@]}"
结果:
arr indexes are 0 1 2 5

if 控制语句

控制语句用于根据条件执行不同的命令,常见的控制语句包括 if 语句。

单条件

语法:

如果 expression 为真,则执行 statements。

cpp 复制代码
if [ expression ]; then
    statements
fi
cpp 复制代码
示例:
age=18
if [ $age == 18 ]; then
    echo "You are an adult."
fi
结果:
You are an adult.
如果 age 等于 18,则输出 "You are an adult."

多条件与

语法:

如果 expression_1 和 expresion_2 都为真,则执行 statements。

cpp 复制代码
if [ expression_1 ] && [ expression_2 ]; then
    statements
fi
cpp 复制代码
示例:
age=18
country="USA"
if [ $age -ge 18 ] && [ "$country" == "USA" ]; then
    echo "You are an adult in the USA."
fi
结果:
You are an adult in the USA.
如果 age 大于或等于 18 且 country 等于 "USA",则输出 "You are an adult in the USA."。

多条件或

语法:

如果 expreion_1 或 expresion_2 为真,则执行 statements。

cpp 复制代码
示例:
age=16
country="USA"
if [ $age == 18 ] || [ "$country" == "USA" ]; then
    echo "You are either an adult or in the USA."
fi
结果:
You are either an adult or in the USA.
如果 age 等于 18 或 country 等于 "USA",则输出 "You are either an adult or in the USA."。

多分支

语法:

如果 expression_1 为真,则执行第一个 statements;否则,如果 expression_2 为真,则执行第二个 statements;如果都不为真,则执行 else 部分的 statements。

cpp 复制代码
if [ expression_1 ]; then
    statements
elif [ expression_2 ]; then
    statements
else
    statements
fi
cpp 复制代码
示例:
age=17
if [ $age -ge 18 ]; then
    echo "You are an adult."
elif [ $age -ge 13 ]; then
    echo "You are a teenager."
else
    echo "You are a child."
fi
结果:
You are a teenager.
根据 age 的值输出相应的消息。

循环语句

在 Bash 编程中,循环语句用于重复执行一组命令,主要有for循环和while循环。

for 循环

for 循环用于遍历列表中的每一个元素,并对每一个元素执行相同的一组命令。

基本语法:

cpp 复制代码
for variable in list; do
    commands
done

在这个语法中,variable 是一个临时变量,它依次取 list 中的每一个值,然后执行 commands。

cpp 复制代码
示例:
for fruit in apple banana cherry; do
    echo $fruit
done
结果:
apple
banana
cherry
这个循环遍历了apple、banana 和 cherry,并依次打印它们。

表达式循环

for 循环也可以通过表达式来控制循环次数。

基础语法:

cpp 复制代码
for (( expression1; expression2; expression3 )); do
    commands
done

在这个语句中,expression1 用于初始化循环变量,expression2 用于设置循环继续的条件,expression3 用于更新循环变量。

cpp 复制代码
示例:
for ((i = 1; i <= 5; i++)); do
    echo $i
done
结果:
1
2
3
4
5
这个循环从 1 开始,每次循环后变量i增加 1,直到i大于 5。

循环范围

通过大括号 {} 可以指定一个范围来循环。

cpp 复制代码
示例:
for num in {5..0..1}; do
    echo $num
done
结果:
5
4
3
2
1
0
这个循环从 5 开始,每次减少 1,直到 0.

循环数组

for循环也可以用来遍历数据中的每一个元素。

cpp 复制代码
示例:
arr=("Welcome" "to" "beforthing")
for i in "${arr[@]}"; do
    echo $i
done
结果:
Welcome
to
beforthing
这个循环遍历数据arr中的每一个元素,并依次打印它们。

@ 与 * 的区别

{arr\[@\]} 和 {arr[*]} 都可以用来引用数据的所有元素,但在某些情况下会有区别

cpp 复制代码
示例:
arr=("Welcome" "to" "beforthing")

# 使用 @
for i in ${arr[@]}; do
    echo $i
done

# 使用 *
for i in ${arr[*]}; do
    echo $i
done

# 使用双引号和 *
for i in "${arr[*]}"; do
    echo $i
done
结果:


# 使用 @
Welcome
to
beforthing

# 使用 *
Welcome
to
beforthing

# 使用双引号和 *
Welcome to beforthing
使用 ${arr[@]} 或 ${arr[*]} 会将数组展开为单个字符串。
使用双引号和 ${arr[*]} 会将数组的所有元素当作一个字符串处理。

while 循环

while循环用于在满足某个条件时重复执行一组命令。

基本语法:

cpp 复制代码
while [ expression ]; do
    commands
done

在这个语法中,当expression为 True 时,执行commands,直到expression为 False。

cpp 复制代码
示例:
count=1
while [ $count -le 5 ]; do
    echo $count
    ((count++))
done
输出:
1
2
3
4
5
这个循环从count等于 1 开始,每次循环后count增加 1,直到count大于 5。

break 与 continue

break 和 continue 是俩种用于控制循环流程的命令。

  • break 语句可以终止循环的执行。
  • continue语句可以路过循环中的某些命令,继续下一次循环。
break 示例
cpp 复制代码
for i in {1..5}; do
    if [ $i == 3 ]; then
        break
    fi
    echo $i
done
结果:
1
2
当 i 等于 3 时,break 语句终止了循环。
continue 示例
cpp 复制代码
for i in {1..5}; do
    if [ $i == 3 ]; then
        continue
    fi
    echo $i
done
结果:
1
2
4
5
当 i 等于 3 时,continue 语句路过了当前的循环迭代,继续下一次循环。

Bash 函数

定义函数

基本语法:

cpp 复制代码
function_name(){
  commands
}

变量的作用域

  • 默认情况下所有变量都定义为全局变量,即使在函数内部声明也是如此。
  • 使用local关键字在函数内部声明局部变量,该变量只能够在该函数内部使用。

返回值

  • Bash 函数中,其返回值是执行的最后一个语句的状态,1-255(十进制)范围内表示失败,除此之外表示成功。
  • 想要从函数中返回任意实际的值,最简单的选择是将函数的执行结果分配给一个全局变量。
  • 更好的选择是将值发送到 stdout 再打印输出。

参数传递

  • $0 为函数本身
  • $1、2⋅⋅⋅2···2⋅⋅⋅n 参数传递的顺序位
  • $# 保存传递给函数的函数的位置参数或数量
  • 当前进程 ID 号

  • $? 显示最后一个命令的退出状态,0 表示正常,其他表示错误退出

案例

  • 案例 1,判断一个数字是否为正数
cpp 复制代码
#!/bin/bash

# 判断输入的数字是否为正数
check_positive() {
    if [ $1 -gt 0 ]; then
        echo "$1 是正数"
    else
        echo "$1 不是正数"
    fi
}

# 调用函数并传递参数
check_positive 5
check_positive -3
相关推荐
Luna-player2 小时前
Linux 用户、用户组及权限管理,相关个人学习笔记
linux·笔记·学习
前端小趴菜~时倾2 小时前
自我提升-python爬虫学习:day01
爬虫·python·学习
星幻元宇VR2 小时前
VR消防安全学习机|让安全教育更立体、更真实
科技·学习·安全·vr·虚拟现实
怪侠_岭南一只猿2 小时前
爬虫工程师学习路径 · 阶段五:数据存储与清洗(完整学习文档)
爬虫·python·学习
KevinGuo4572 小时前
【前后端开发知识 - 边开发边学习】什么的单元测试、集成测试和E2E测试?
学习·单元测试·集成测试
red_redemption2 小时前
自由学习记录(136)
学习
EnglishJun2 小时前
ARM嵌入式学习(二) --- 入门51(中断)
arm开发·学习
for_ever_love__3 小时前
Objective-C学习 NSArray 和 NSMutableArray 功能详解
学习·ios·objective-c
Pyeako3 小时前
自然语言学习--bert框架
人工智能·深度学习·学习·bert·lstm·自然语言学习