当前位置: 首页 > news >正文

Shell 脚本入门:从零开始写自动化脚本

目录

一、Shell 、Shell 命令、Shell 脚本

二、常用 Shell 命令与注释写法

三、echo 命令的使用

四、Shell 变量类型

五、变量与参数使用

六、读取用户输入

七、算术运算

八、条件判断与流程控制

九、循环结构

十、函数定义与调用


一、Shell 、Shell 命令、Shell 脚本

1、Shell 是什么?

Shell 是操作系统与用户之间的桥梁,它接收用户输入的命令,并调用系统内核去执行相应的任务。在 Linux 系统中,最常用的 Shell 是 Bash(Bourne Again Shell)。我们平时在终端中输入的命令,实际上都是通过 Shell 来解析和执行的。

Shell 不仅是一个交互工具,更是一种具备编程能力的“命令解释器”。它允许我们将多个命令写入一个脚本文件中,批量执行,从而实现自动化操作。

2、Shell 命令是什么?

Shell 命令是 Linux 系统操作的核心工具,比如我们常用的 lscdcpecho 等命令,都是在 Shell 中运行的指令。

需要注意的是:

  • ls 是一个命令(程序)

  • Shell 是一个解释器(工具)

  • 你输入的 ls 命令是由 Shell 接收并解析,交给系统执行的

换句话说,Shell 是“命令解释器”,ls 是 Shell 能调用的“命令”

3、什么是 Shell 脚本?

Shell 脚本(Shell Script) 是一系列 Shell 命令的集合,保存在一个文本文件中,按照顺序依次执行。

通俗地讲:你在终端一个个敲的命令,可以提前写进一个 .sh 文件中,将其变成一个“可执行的任务集合”,以后只需要运行这个文件,就能一次性执行所有操作,无需手动重复输入。

总结一句话:

Shell 是工具,负责与系统交互

Shell 命令是操作单位,如 ls, rm, echo(常用的liunx命令很多都是shell命令)

Shell 脚本是程序,可以批量执行命令,实现自动化处理

二、常用 Shell 命令与注释写法

1、创建shell脚本: 

Shell 脚本(Shell Script)是将多个命令按照顺序写入一个文件中,通过一次执行这个文件,来自动完成一系列任务。文件名通常以 .sh 结尾,但是这不是必须的,以.SH结尾只是更好人程序员知道这是个shell脚本

touch demo.sh

2、shell脚本的开头:

首先以如下开头:

#!/bin/bash  

这一行叫做 “shebang(哈希邦)”,它是所有 Shell 脚本中非常重要的一行,

作用是:指定脚本的解释器,告诉操作系统用 /bin/bash 这个程序来解释执行当前脚本。

3、注释的使用:

#->单行注释

:<<!

    多行注释

#!/bin/bash  # 单行注释
# 这是一个单行注释# 多行注释(使用 Here 文档技巧)
:<<!
这是一段多行注释
可以写很多行
!

 如下是一个简单的案例: 

#!/bin/bash
#单行注释
:<<!
多行注释
!
#输出printf
echo "hello shell"
#创建文件夹
mkdir ./one
#创建文件
touch ./txt.txt
#在txt.txt写入数据
echo "hello shell">>./txt.txt

4、执行方法:

bash demo.sh   #利用bash命令执行脚本文件,本质就是使用Shell解析器运行脚本文件

sh demo.sh  #用sh命令执行脚本文件,本质就是使用Shell解析器运行脚本文件

# 或者
chmod +x demo.sh
./demo.sh

#执行当前目录下的脚本文件
#脚本文件自己执行需要具有可执行权限,否则无法执行

区别:sh或bash执行脚本文件方式是直接使用Shell解析器运行脚本文件,不需要可执行权限仅路径方式是执行脚本文件自己,需要可执行权限

 

三、echo 命令的使用

echo 是 Shell 脚本中非常常用的命令,它用于向终端输出文本、变量的值,或者将输出内容重定向到文件。了解 echo 的各种用法,可以帮助你更好地调试脚本、展示结果或保存数据。

1、 基本语法

echo [选项] [字符串]

选项:用于修改 echo 命令的行为(如是否输出换行符、是否支持转义字符等)。

字符串:是你想要输出的文本、变量等内容。

2、常用选项

  1. -n:不输出换行符

    • 默认情况下,echo 会输出换行符,如果你不想要换行符,可以使用 -n 选项。

    echo -n "Hello, World!"
    echo "This is on the same line."
    

    输出:

    Hello, World!This is on the same line.
    
  2. -e:启用转义字符

    • 默认情况下,echo 不会解析一些特殊的转义字符,如 \n\t 等。使用 -e 选项后,echo 会解析这些转义字符。

    echo -e "Hello\nWorld"
    echo -e "Name\tAge"
    

    输出:

    Hello
    World
    Name    Age
    
  3. -E:禁用转义字符

    • 如果你不想让 echo 解析转义字符,可以使用 -E 选项。

    echo -E "Hello\nWorld"
    

    输出:

    Hello\nWorld
    

3、输出变量的值

echo 很常用于输出变量的值:

name="Alice"
echo "Hello, $name!"

输出:

Hello, Alice!

你也可以使用大括号来明确变量范围,特别是在变量名后面跟着其他字符时:

name="Alice"
echo "Hello, ${name}123!"

输出:

Hello, Alice123!

4、输出文本到文件

你还可以将 echo 的输出重定向到文件中:

echo "This is a test." > test.txt
  • 使用 > 会将内容写入文件并覆盖原有内容。

  • 使用 >> 会将内容追加到文件末尾。

echo "This is another test." >> test.txt

5、 结合脚本和输入输出

在 Shell 脚本中,echo 常常用于输出调试信息或者展示用户输入的结果:

#!/bin/bash
echo "Please enter your name:"
read name
echo "Hello, $name!"

运行后,脚本会提示用户输入名字并输出问候语:

Please enter your name:
Alice
Hello, Alice!

完整代码: 

#!/bin/bash  
echo  
echo -n "Hello, World!"
echo "This is on the same line."
echo  
echo -e "Hello\nWorld"
echo -e "Name\tAge"
echo  
echo -E "Hello\nWorld"
echo
name="Alice"
echo "Hello, $name!"
echo
name="Alice"
echo "Hello, ${name}123!"
echo
echo "This is a test." > test.txt
echo
echo "Please enter your name:"
read name
echo "Hello, $name!"

运行结果: 

6、总结

用法示例说明
输出文本echo "Hello, World"输出指定的文本
不换行输出echo -n "Hello"不换行
启用转义字符echo -e "Hello\nWorld"启用转义字符
输出变量值echo "Hello, $name"输出变量的值
输出到文件echo "Text" > file.txt输出内容并覆盖文件
追加到文件echo "Text" >> file.txt追加内容到文件末尾

四、Shell 变量类型

Shell 中的变量可以分为以下几类:

1、系统环境变量(Environment Variables)

这些变量由系统定义,用于控制 Shell 的运行环境。常见的系统环境变量包括:

变量名含义说明
PATH可执行文件的搜索路径
HOME当前用户的主目录路径
SHELL使用的 Shell 类型(如 /bin/bash
USER当前用户名
PWD当前工作目录
LANG语言与地区设置

示例:

echo $HOME
echo $USER
echo $PATH

设置环境变量:

export VAR_NAME=value   # 临时设置

若想永久生效,可写入 ~/.bashrc~/.profile 等配置文件。

 二、自定义变量(User-defined Variables)

由用户在脚本中定义,用于存储值或中间结果。

1、定义变量:

变量定义规则
        1.变量名称可以有字母,数字和下划线组成,但是不能以数字开头

        ⒉.等号两侧不能有空格
        3.在bash环境中,变量的默认类型都是字符串类型,无法直接进行数

        4.变量的值如果有空格,必须使用双引号括起来
        5.不能使用Shell的关键字作为变量名称

name="Tom"
age=20

使用变量:

echo "My name is $name, I am $age years old."

注意事项:

=两边不能有空格。

变量名区分大小写。

 2、局部变量(函数中)使用 local 关键字:

myfunc() {local temp="hello"echo $temp
}

3、declare

是 Bash 中的一个内建命令,主要用于声明变量并设置其属性,相比于普通的赋值,它可以精细控制变量的类型和行为。

 declare 的基本用法

declare [选项] 变量名=值

常用选项

选项说明
-r只读变量(readonly)
-i整数变量,只能执行数学运算
-a数组变量
-A关联数组变量(键值对)
-x导出为环境变量(类似 export)
-f显示已定义的函数
-p显示变量定义信息

示例详解

 声明只读变量

declare -r pi=3.14
pi=3.14159   # 报错:只读变量不能修改

声明整数变量并进行计算

declare -i num=5
num=num+3
echo $num  # 输出:8

注意:如果 num="hello",则输出为 0,因为字符串不能当作整数。

 声明数组变量

declare -a fruits=("apple" "banana" "cherry")
echo ${fruits[1]}  # banana

 声明关联数组(Bash 4+)

declare -A info
info[name]="Tom"
info[age]=22
echo ${info[name]}  # Tom

查看变量声明信息

declare -p fruits
declare -p info

将变量声明为环境变量(类似 export

declare -x user="Alice"

 declarelocal 的关系

在函数内部,如果你想限制变量作用域为函数内,使用:

local var="inside"

或者结合 declare

local -i count=0

 小结

命令说明
declare控制变量属性(类型、安全性)
declare -i整数运算变量
declare -r设置只读变量
declare -a/-A声明数组/关联数组
declare -x类似 export,用于设置环境变量

5、export 的作用

export 是 Shell 中用于 设置环境变量 的关键命令,它的作用是将变量从当前 Shell 中导出,使其对子进程(如脚本或其他程序)可见。

当你使用 export 时,变量就从“局部变量”变成了“环境变量”。

简单说有点类似与C语言中的“extern”关键字

变量名=值
export 变量名

或者直接写成一行:

export 变量名=值

 示例演示

不使用 export

#!/bin/bash
var1="hello"
./child.sh

child.sh 内容:

#!/bin/bash
echo $var1   # 输出为空

说明:子脚本 child.sh 无法访问父脚本中定义的变量 var1

使用 export

#!/bin/bash
export var1="hello"
./child.sh

现在 child.sh 能正确输出:

hello

小知识

  • 只对当前 shell 会话及其子进程有效。

  • 若想永久设置,可写入 ~/.bashrc~/.profile 等文件。

  • 查看当前所有环境变量:

    export
    env
    

 env  #查看系统环境变量

 小结

命令作用
export var=value设置环境变量,子进程可访问
export显示所有已导出的环境变量

3、特殊符号变量(位置参数与特殊符号)

这些变量由 Shell 自动维护,用于获取命令行参数、状态等信息。

变量含义
$0当前脚本名称
$1~$9第1~9个位置参数
${10}第10个及以上的参数
$#参数个数
$*所有参数(作为一个整体)
$@所有参数(逐个分隔)
$?上一条命令的退出状态(0 成功,非0 失败)
$$当前脚本的进程 ID
$!上一个后台命令的进程 ID

示例:

echo "n1=$1 n10=${10}"
echo "all* :$*"
echo "all@ :$@"
for n in "$*"
doecho $n
done 
for n in "$@"
do echo $n
doneecho "n_num=:"$#

小结

类别作用示例
环境变量控制系统或 Shell 行为PATH, HOME
自定义变量储存数据或临时值name="Alice"
特殊变量获取状态、参数等系统信息$0, $#, $?

五、变量与参数使用

变量

1. 变量赋值

在 Shell 中,变量不需要显式地声明类型。变量的赋值格式为:

variable_name=value
  • 赋值时,= 两边不能有空格。

  • 变量名通常由字母、数字、下划线组成,但不能以数字开头。

例如:

name="Alice"
age=25
2. 引用变量

要引用变量的值,需要在变量名前加上 $

echo "Name: $name"
echo "Age: $age"

输出:

Name: Alice
Age: 25
3. 使用大括号引用变量

如果你在引用变量时,后面紧接着其他字符(如数字、字母等),可以使用大括号来明确变量的边界:

echo "Name: ${name}123"

输出:

Name: Alice123
4. 只读变量

如果你想定义一个只读变量,可以使用 readonly

readonly name="Alice"

尝试修改只读变量会报错:

name="Bob"  # 会报错
5. 环境变量

你也可以通过 export 命令将变量导出为环境变量,这样其他进程也能访问这个变量。

export name="Alice"

位置参数

位置参数是脚本或函数接受的命令行参数。位置参数通过 $1$2 等来引用,$0 通常代表脚本本身的文件名。

1. 获取位置参数
#!/bin/bash
# 获取位置参数
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"

假设你运行脚本时输入以下命令:

./demo.sh Alice 25

输出:

Script name: ./demo.sh
First argument: Alice
Second argument: 25
2. 特殊参数
  • $#:表示脚本或函数接受的参数个数(即位置参数的数量)。

echo "Number of arguments: $#"
  • $*$@:表示所有位置参数(字符串数组),两者的区别在于:

    • $*:会将所有参数当作一个单独的字符串。

    • $@:会将每个参数作为一个独立的字符串。

echo "All arguments as a single string: $*"
echo "All arguments as separate strings: $@"
3. 通过位置参数传递给函数
#!/bin/bash
my_function() {echo "First argument: $1"echo "Second argument: $2"
}my_function "Alice" "Bob"

输出:

First argument: Alice
Second argument: Bob

 默认参数

在实际编程中,我们可能需要为某些参数设置默认值。可以使用 ${parameter:-default} 来实现,如果参数为空或未设置,则使用默认值。

#!/bin/bash
name=${1:-"Guest"}  # 如果未传递第一个参数,则使用 "Guest" 作为默认值
echo "Hello, $name!"

如果你执行以下命令:

./demo.sh Alice

输出:

Hello, Alice!

如果你执行时不传递参数:

./demo.sh

输出:

Hello, Guest!

变量操作

  1. 获取字符串长度

你可以使用 ${#variable} 获取变量内容的长度:

str="Hello"
echo "Length of string: ${#str}"

输出:

Length of string: 5
  1. 字符串替换

  • 替换字符串中的第一个匹配项:

str="Hello World"
echo "${str/World/Shell}"

输出:

Hello Shell
  • 替换字符串中的所有匹配项:

str="Hello World World"
echo "${str//World/Shell}"

输出:

Hello Shell Shell
  1. 子字符串提取

你可以通过 ${variable:start:length} 来提取子字符串:

str="Hello World"
echo "${str:6:5}"

输出:

World

完整代码:

#!/bin/bash  
echo  
name="Alice"
age=25
echo "Name: $name"
echo "Age: $age"
echo "Name: ${name}123"
echo# 获取位置参数
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo
echo "Number of arguments: $#"
echo
echo "All arguments as a single string: $*"
echo "All arguments as separate strings: $@"
echo
my_function() {echo "First argument: $1"echo "Second argument: $2"
}
my_function "Alice" "Bob"
echo
str="Hello"
echo "Length of string: ${#str}"
echo
str="Hello World"
echo "${str/World/Shell}"
echo
str="Hello World World"
echo "${str//World/Shell}"
echo
str="Hello World"
echo "${str:6:5}"
echo

运行结果:

 总结

内容示例说明
变量赋值name="Alice"变量赋值,不能有空格
引用变量echo $name输出变量的值
位置参数$1, $2, ...获取命令行传递的参数
获取参数个数$#获取传递的参数个数
获取所有参数$*, $@获取所有参数
默认参数name=${1:-"Guest"}如果没有传递参数则使用默认值
字符串长度${#str}获取字符串的长度
字符串替换${str/World/Shell}替换字符串中的某部分
子字符串提取${str:6:5}获取子字符串

通过掌握变量和参数的使用,可以让你的 Shell 脚本更加灵活、功能更强大。如果有需要进一步学习 Shell 函数、数组等内容,也可以继续深入。

六、读取用户输入

在 Shell 脚本中,读取用户输入是常见的需求。你可以通过不同的命令来接收用户的输入并根据输入的内容进行处理。常见的读取用户输入的方法有 read 命令,它可以帮助我们从标准输入(通常是终端)中获取数据。

 使用 read 命令

1. 基本用法

read 命令用于从用户输入获取一行数据并将其赋值给指定的变量。

#!/bin/bash
# 读取用户输入
read name
echo "Hello, $name!"

运行脚本后,脚本会等待用户输入,输入完成后按回车,脚本会输出 Hello, [用户输入的内容]

例如:

$ ./demo.sh
Alice
Hello, Alice!

2. 读取多个变量

如果你想读取多个输入项,可以在 read 命令后列出多个变量,输入的内容会按照空格进行分割,依次赋给每个变量。

#!/bin/bash
# 读取多个变量
read name age
echo "Name: $name, Age: $age"

执行脚本时,用户输入两个值并用空格隔开:

$ ./demo.sh
Alice 25
Name: Alice, Age: 25

3. 提示信息

你可以在使用 read 命令时,添加提示信息,提示用户输入的内容:

#!/bin/bash
# 添加提示信息
read -p "Please enter your name: " name
echo "Hello, $name!"

这会在提示信息后等待用户输入:

$ ./demo.sh
Please enter your name: Alice
Hello, Alice!

4. 设置输入超时

可以通过 -t 选项来设置输入的超时时间,单位是秒。如果在指定时间内用户没有输入,read 命令会自动退出。

#!/bin/bash
# 设置 5 秒的输入超时
read -t 5 -p "Please enter your name: " name
if [ -z "$name" ]; thenecho "You took too long to respond!"
elseecho "Hello, $name!"
fi

如果超时未输入,输出:

You took too long to respond!

5. 隐藏输入内容

有时你可能需要用户输入密码或其他敏感信息,此时可以使用 -s 选项来隐藏输入内容。

#!/bin/bash
# 隐藏输入内容(如密码)
read -sp "Enter your password: " password
echo
echo "Password entered."

此时输入的内容会被隐藏,不会显示在屏幕上。

6. 读取一个字符

-n 选项可以让 read 命令只读取用户输入的一个字符:

#!/bin/bash
# 只读取一个字符
read -n 1 -p "Do you want to continue (y/n)? " choice
echo
echo "You chose: $choice"

在这种情况下,用户只需要输入一个字符(例如 yn),然后按回车,脚本就会继续执行。

7. 输入内容的分隔符

默认情况下,read 命令会将用户输入的内容按空格分割成多个部分。如果你希望使用其他字符作为分隔符,可以使用 IFS(内部字段分隔符)变量。

#!/bin/bash
# 改变分隔符为逗号
IFS=',' read -p "Enter name,age: " name age
echo "Name: $name, Age: $age"

执行时,用户输入内容需要用逗号分隔:

$ ./demo.sh
Enter name,age: Alice,25
Name: Alice, Age: 25

示例:读取用户信息并进行判断

#!/bin/bash
# 读取用户输入的姓名和年龄
read -p "Enter your name: " name
read -p "Enter your age: " age# 判断年龄
if [ "$age" -ge 18 ]; thenecho "$name, you are an adult."
elseecho "$name, you are a minor."
fi

如果输入:

Enter your name: Alice
Enter your age: 20

输出:

Alice, you are an adult.

完整代码:

#!/bin/bash
# 读取用户输入
read name
echo "Hello, $name!"
echo
# 读取多个变量
read name age
echo "Name: $name, Age: $age"
echo
# 添加提示信息
read -p "Please enter your name: " name
echo "Hello, $name!"
echo
# 设置 5 秒的输入超时
read -t 5 -p "Please enter your name: " name
if [ -z "$name" ]; thenecho "You took too long to respond!"
elseecho "Hello, $name!"
fi
echo
# 隐藏输入内容(如密码)
read -sp "Enter your password: " password
echo
echo "Password entered."
echo
# 只读取一个字符
read -n 1 -p "Do you want to continue (y/n)? " choice
echo
echo "You chose: $choice"
# 改变分隔符为逗号
IFS=',' read -p "Enter name,age: " name age
echo "Name: $name, Age: $age"
echo
# 读取用户输入的姓名和年龄
read -p "Enter your name: " name
read -p "Enter your age: " age
echo
# 判断年龄
if [ "$age" -ge 18 ]; thenecho "$name, you are an adult."
elseecho "$name, you are a minor."
fi

运行结果:

总结

命令选项说明示例
read读取用户输入并赋值给变量read name
-p显示提示信息read -p "Enter name: " name
-t设置超时时间(秒)read -t 5 -p "Enter name: " name
-s隐藏输入内容read -sp "Enter password: " pwd
-n只读取一个字符read -n 1 -p "Continue? " choice
IFS设置输入分隔符IFS=',' read name age

通过 read 命令,你可以轻松地获取用户的输入,并根据输入的内容做出相应的处理,提升脚本的交互性和灵活性。

七、算术运算

在 Shell 脚本中,算术运算是常见的需求,可以用来进行基本的数学计算(如加、减、乘、除、取余等)。Shell 提供了几种方法来进行算术运算。

1、 使用 expr 进行算术运算

expr 是一个用于计算表达式的命令,它可以用于执行加法、减法、乘法、除法、取余等运算。注意,expr 必须在运算符周围加上空格。

1. 加法
#!/bin/bash
a=10
b=20
sum=$(expr $a + $b)
echo "Sum: $sum"

输出:

Sum: 30
2. 减法
#!/bin/bash
a=30
b=10
diff=$(expr $a - $b)
echo "Difference: $diff"

输出:

Difference: 20
3. 乘法
#!/bin/bash
a=5
b=6
prod=$(expr $a \* $b)   # 注意乘法符号需要加反斜杠
echo "Product: $prod"

输出:

Product: 30
4. 除法
#!/bin/bash
a=30
b=5
quotient=$(expr $a / $b)
echo "Quotient: $quotient"

输出:

Quotient: 6
5. 取余
#!/bin/bash
a=10
b=3
remainder=$(expr $a % $b)
echo "Remainder: $remainder"

输出:

Remainder: 1

2、 使用 $(( )) 进行算术运算

除了 expr,Shell 还支持使用 $(( )) 进行算术运算,这种方式更为简洁,也不需要在运算符两侧加空格。

1. 加法
#!/bin/bash
a=10
b=20
sum=$((a + b))
echo "Sum: $sum"

输出:

Sum: 30
2. 减法
#!/bin/bash
a=30
b=10
diff=$((a - b))
echo "Difference: $diff"

输出:

Difference: 20
3. 乘法
#!/bin/bash
a=5
b=6
prod=$((a * b))   # 乘法时不需要反斜杠
echo "Product: $prod"

输出:

Product: 30
4. 除法
#!/bin/bash
a=30
b=5
quotient=$((a / b))
echo "Quotient: $quotient"

输出:

Quotient: 6
5. 取余
#!/bin/bash
a=10
b=3
remainder=$((a % b))
echo "Remainder: $remainder"

输出:

Remainder: 1

3、使用 let 进行算术运算

let 是另一种进行算术运算的方式,它直接在 Shell 脚本中进行计算,而不需要使用 $(( ))expr

1. 加法
#!/bin/bash
a=10
b=20
let sum=a+b
echo "Sum: $sum"

输出:

Sum: 30
2. 减法
#!/bin/bash
a=30
b=10
let diff=a-b
echo "Difference: $diff"

输出:

Difference: 20
3. 乘法
#!/bin/bash
a=5
b=6
let prod=a*b
echo "Product: $prod"

输出:

Product: 30
4. 除法
#!/bin/bash
a=30
b=5
let quotient=a/b
echo "Quotient: $quotient"

输出:

Quotient: 6
5. 取余
#!/bin/bash
a=10
b=3
let remainder=a%b
echo "Remainder: $remainder"

输出:

Remainder: 1

4 、自增和自减

Shell 还支持对变量进行自增和自减操作,使用 ++-- 操作符。

1. 自增
#!/bin/bash
a=5
((a++))
echo "After increment: $a"

输出:

After increment: 6
2. 自减
#!/bin/bash
a=5
((a--))
echo "After decrement: $a"

输出:

After decrement: 4

完整代码:

#!/bin/bash
a=10
b=20
sum=$(expr $a + $b)
echo "Sum: $sum"
echo
a=30
b=10
diff=$(expr $a - $b)
echo "Difference: $diff"
echo
a=5
b=6
prod=$(expr $a \* $b)   # 注意乘法符号需要加反斜杠
echo "Product: $prod"
echo
a=30
b=5
quotient=$(expr $a / $b)
echo "Quotient: $quotient"
echo
a=10
b=3
remainder=$(expr $a % $b)
echo "Remainder: $remainder"
echo
a=10
b=20
sum=$((a + b))
echo "Sum: $sum"
echo
a=30
b=10
diff=$((a - b))
echo "Difference: $diff"
echo
a=5
b=6
prod=$((a * b))   # 乘法时不需要反斜杠
echo "Product: $prod"
echo
a=30
b=5
quotient=$((a / b))
echo "Quotient: $quotient"
echo
a=10
b=3
remainder=$((a % b))
echo "Remainder: $remainder"
echo
a=10
b=20
let sum=a+b
echo "Sum: $sum"
echo
a=30
b=10
let diff=a-b
echo "Difference: $diff"
echo
a=5
b=6
let prod=a*b
echo "Product: $prod"
echo
a=30
b=5
let quotient=a/b
echo "Quotient: $quotient"
a=10
b=3
let remainder=a%b
echo "Remainder: $remainder"
echo
a=5
((a++))
echo "After increment: $a"
echo
a=5
((a--))
echo "After decrement: $a"
echo

运行结果:

5、小结

运算符说明示例
+加法sum=$((a + b))
-减法diff=$((a - b))
*乘法prod=$((a * b))
/除法quotient=$((a / b))
%取余remainder=$((a % b))
++自增((a++))
--自减((a--))
expr通过 expr 进行计算expr $a + $b

以上命令只能用于整数,不支持浮点数

6、bc 命令:功能强大的计算器工具

在 Shell 中,如果需要进行 浮点数运算 或者更复杂的数学表达式,bc 是非常实用的工具。bc 是 Linux 中内建的 任意精度计算器语言(basic calculator),支持变量、函数和控制结构。

基本语法
echo "表达式" | bc

例如:

echo "3 + 5" | bc         # 输出 8
echo "scale=2; 3.5 / 2" | bc  # 输出 1.75,保留两位小数
 示例:基本运算
#!/bin/basha=3.5
b=1.2sum=$(echo "$a + $b" | bc)
echo "sum = $sum"sub=$(echo "$a - $b" | bc)
echo "sub = $sub"mul=$(echo "$a * $b" | bc)
echo "mul = $mul"div=$(echo "scale=3; $a / $b" | bc)
echo "div = $div"

输出:

sum = 4.7
sub = 2.3
mul = 4.2
div = 2.916
 scale 的含义

scale 用来设置小数点后保留的位数:

echo "scale=3; 10 / 3" | bc   # 输出 3.333

如果不设置 scale,默认结果为整数部分。

好的,下面是你博客中关于 bc 计算器中常用的几个设置参数(scaleibaseobase)的详细说明内容,可以作为附加补充部分放在 “bc 命令” 小节之后,逻辑清晰、排版规范:


 scale / ibase / obase 用法详解

bc 中支持设置以下三个控制变量,用于精度与进制转换:


 scale:小数点后保留位数
  • 作用:设置小数点后保留几位精度(仅对除法等有意义)。

  • 语法:scale=数字

示例:

echo "scale=2; 5 / 3" | bc       # 输出:1.66
echo "scale=5; 1.234 / 3" | bc   # 输出:0.41133

scale 默认值为 0,所以如果不设置,bc 默认只输出整数部分!


sibase:输入数值的进制(Input Base)
  • 作用:指定你输入的数字是几进制。

  • 默认:ibase=10

  • 常与 obase 搭配使用实现 进制转换

示例:十六进制转十进制

echo "ibase=16; A + 1" | bc   # 输出:11(即十进制)

注意:ibase 要在 obase 之前设置! 因为设置 ibase 后,后面所有数值都会以该进制解析。

示例:进制转换(十进制转二进制)

echo "obase=2; 10" | bc      # 输出:1010(二进制)

 obase:输出数值的进制(Output Base)
  • 作用:设置计算结果的输出进制。

  • 默认:obase=10

示例:将十进制 100 转换为十六进制

echo "obase=16; 100" | bc    # 输出:64

注意事项
  • 设置顺序 matters:

    • ibase 一定要在 obase 前设置

    • 因为当 ibase 被设置为非 10 后,后续数字(包括 obase 的值)也将按新进制解析!

错误示例:

echo "ibase=16; obase=10; A" | bc    # 错误:obase 会被当成十六进制解释

正确示例:

echo "obase=10; ibase=16; A" | bc    # 输出 10

小结表格

参数说明默认值示例
scale小数精度控制0scale=3; 10/33.333
ibase输入数字的进制(Input Base)10ibase=2; 110012
obase输出结果的进制(Output Base)10obase=2; 121100

如果你希望我把这些内容连同前面章节统一整理成一篇完整的 Shell 博客结构(比如 .md 格式),我可以直接帮你生成!你想整理成一个 Markdown 文件吗?

进阶功能:使用 bc -l

加上 -l 参数可以引入 math 库,支持 sine, cosine, sqrt() 等函数:

echo "scale=4; s(1.0)" | bc -l      # 计算 sin(1.0)
echo "scale=4; sqrt(2)" | bc -l     # 平方根
多表达式计算

可以一次性执行多条命令:

echo "a=5; b=3; a*b + a/b" | bc -l
 交互模式(命令行里直接打 bc
$ bc
scale=2
3.14 * 2
6.28
quit

总结对比

特性letbc
支持浮点数不支持 支持
精度控制不支持scale=n 控制
使用方式Shell 内建管道传入表达式
功能扩展性基本运算支持复杂表达式和逻辑

如果你在写 Shell 脚本时只处理整数,let 足够了;
但如果涉及到浮点数精度计算或者数学函数,推荐使用 bc

八、条件判断与流程控制

Shell 脚本中的条件判断和流程控制用于根据不同的条件执行不同的命令或代码块。在实际编写脚本时,我们经常需要用到 if 判断语句、case 语句、for 循环、while 循环等结构来控制程序的执行流程。

1、if 判断语句

if 语句是用来根据条件是否成立来决定是否执行某个代码块。它的基本语法结构如下:

if condition
thencommand1command2...
elif condition2
thencommand3
elsecommand4
fi
  • if:用来测试一个条件表达式,若条件为真(0),则执行 then 后面的代码块。

  • elif:可选,用来判断另一个条件,若为真则执行相应代码。

  • else:可选,若前面的条件都不成立,则执行 else 后面的代码块。

1. 基本用法
#!/bin/bash
a=10
if [ $a -gt 5 ]
thenecho "$a is greater than 5"
elseecho "$a is not greater than 5"
fi

输出:

10 is greater than 5
2. 多个条件判断
#!/bin/bash
a=10
b=20
if [ $a -gt $b ]
thenecho "$a is greater than $b"
elif [ $a -eq $b ]
thenecho "$a is equal to $b"
elseecho "$a is less than $b"
fi

输出:

10 is less than 20
条件判断符号
  • -eq:等于

  • -ne:不等于

  • -gt:大于

  • -lt:小于

  • -ge:大于等于

  • -le:小于等于

  • -z:字符串为空

  • -n:字符串非空

2、test[ ] 语法

在 Shell 中,test[ 都用于判断条件,它们的功能相同,可以互换使用。

#!/bin/bash
a=10
if test $a -gt 5
thenecho "$a is greater than 5"
fi

或者

#!/bin/bash
a=10
if [ $a -gt 5 ]
thenecho "$a is greater than 5"
fi

3、 case 结构

case 语句用于多重条件判断,类似于其他编程语言中的 switch 语句。它根据变量的值匹配不同的模式并执行相应的代码块。

#!/bin/bash
echo "Enter a number between 1 and 3"
read numcase $num in1)echo "You chose number 1";;2)echo "You chose number 2";;3)echo "You chose number 3";;*)echo "Invalid number";;
esac

解释:

  • case 后跟要判断的变量 $num

  • 每个条件后用 ) 来进行匹配。

  • ;; 表示匹配完成后的结束。

  • * 是通配符,表示其他情况,即 "默认" 条件。

4、 逻辑运算符

在 Shell 中,你还可以使用逻辑运算符来组合多个条件。

1. AND(与)运算符 &&

当多个条件都满足时,使用 && 来连接。例如,command1 && command2 表示当 command1 执行成功时,才执行 command2

#!/bin/bash
a=10
b=5
if [ $a -gt $b ] && [ $b -gt 0 ]
thenecho "$a is greater than $b and $b is positive"
fi
2. OR(或)运算符 ||

当至少一个条件满足时,使用 || 来连接。例如,command1 || command2 表示当 command1 执行失败时,才执行 command2

#!/bin/bash
a=10
b=15
if [ $a -gt $b ] || [ $b -gt 0 ]
thenecho "At least one condition is true"
fi
3. 非运算符 !

用来否定一个条件的判断。

#!/bin/bash
a=10
if ! [ $a -lt 5 ]
thenecho "$a is not less than 5"
fi

完整代码:

#!/bin/bash
a=10
if [ $a -gt 5 ]
thenecho "$a is greater than 5"
elseecho "$a is not greater than 5"
fi
echo
#!/bin/bash
a=10
b=20
if [ $a -gt $b ]
thenecho "$a is greater than $b"
elif [ $a -eq $b ]
thenecho "$a is equal to $b"
elseecho "$a is less than $b"
fi
echo
a=10
if test $a -gt 5
thenecho "$a is greater than 5"
fi
echo
echo "Enter a number between 1 and 3"
read numcase $num in1)echo "You chose number 1";;2)echo "You chose number 2";;3)echo "You chose number 3";;*)echo "Invalid number";;
esac
a=10
b=5
if [ $a -gt $b ] && [ $b -gt 0 ]
thenecho "$a is greater than $b and $b is positive"
fi
echo
a=10
b=15
if [ $a -gt $b ] || [ $b -gt 0 ]
thenecho "At least one condition is true"
fi
echo
a=10
if ! [ $a -lt 5 ]
thenecho "$a is not less than 5"
fi
echo

运行结果: 

九、循环结构

循环结构是编程语言中的一种基本控制结构,允许程序在特定条件下重复执行某一段代码。在 Shell 脚本中,常用的循环结构包括 for 循环、while 循环和 until 循环,它们用于不同场景下的重复任务。下面详细介绍这三种循环结构。


1、for 循环

for 循环用于遍历一系列值或执行一定次数的操作。Shell 中的 for 循环有两种常见的使用方式:遍历列表和基于计数的循环。

1. 遍历列表
#!/bin/bash
# 使用for遍历一个列表
for i in 1 2 3 4 5
doecho "Iteration: $i"
done

输出:

Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5
2. 遍历文件夹中的文件

你还可以使用 for 循环遍历文件夹中的文件:

#!/bin/bash
for file in /path/to/directory/*
doecho "File: $file"
done
3. 基于计数的循环

如果你知道循环的次数,可以使用 for 循环进行计数:

#!/bin/bash
for i in {1..5}
doecho "Iteration: $i"
done

输出:

Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5

你还可以使用 for 进行更灵活的计数,例如步长控制:

#!/bin/bash
for i in {1..10..2}
doecho "Iteration: $i"
done

输出:

Iteration: 1
Iteration: 3
Iteration: 5
Iteration: 7
Iteration: 9

2、while 循环

while 循环是一种条件循环,当条件为真时,它会重复执行某段代码。通常用于你不确定循环次数,但能判断何时停止循环的场景。

1. 基本用法
#!/bin/bash
# 使用while循环,循环直到条件为假
i=1
while [ $i -le 5 ]
doecho "Iteration: $i"((i++))  # 递增
done

输出:

Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5
2. 使用 read 控制 while 循环

你还可以使用 read 来控制 while 循环,直到用户输入特定的值时才停止循环:

#!/bin/bash
# 使用while循环直到用户输入 'quit'
while true
doread -p "Enter a command (type 'quit' to exit): " commandif [ "$command" == "quit" ]thenecho "Exiting..."breakfiecho "You entered: $command"
done

3、 until 循环

until 循环与 while 循环相反,until 在条件为 时执行,直到条件变为 才停止循环。

1. 基本用法
#!/bin/bash
# 使用until循环,直到条件为真时才停止
i=1
until [ $i -gt 5 ]
doecho "Iteration: $i"((i++))  # 递增
done

输出:

Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5

while 循环的不同之处在于,until 循环当条件为 时执行,当条件变为 时退出。

4、 breakcontinue 控制循环

在循环中,有时我们需要提前跳出循环或跳过当前的迭代。breakcontinue 用于这种场景。

1. break 语句

break 用于退出循环结构(无论条件是否成立),它会立即终止当前的循环。

#!/bin/bash
# 使用break提前退出循环
for i in 1 2 3 4 5
doif [ $i -eq 3 ]thenecho "Breaking the loop at i=$i"breakfiecho "Iteration: $i"
done

输出:

Iteration: 1
Iteration: 2
Breaking the loop at i=3
2. continue 语句

continue 用于跳过当前循环中的其余部分,并立即开始下一次循环迭代。

#!/bin/bash
# 使用continue跳过当前迭代
for i in 1 2 3 4 5
doif [ $i -eq 3 ]thenecho "Skipping the loop at i=$i"continuefiecho "Iteration: $i"
done

输出:

Iteration: 1
Iteration: 2
Skipping the loop at i=3
Iteration: 4
Iteration: 5

在上面的例子中,continue 会跳过数字 3 的输出,继续进行后续的迭代。

5、小结

结构语法说明
forfor var in ... do ... done循环遍历一系列值或执行一定次数的操作
whilewhile condition do ... done条件为真时执行代码块
untiluntil condition do ... done条件为假时执行代码块
breakbreak立即退出循环
continuecontinue跳过当前迭代,继续下一次循环

这些循环结构可以帮助你在 Shell 脚本中实现复杂的逻辑处理,尤其是在需要处理大量数据或反复执行某个任务时非常有用。掌握这些循环结构,你将能够编写更高效、灵活的 Shell 脚本。

完整代码:

#!/bin/bash
# 使用for遍历一个列表
for i in 1 2 3 4 5
doecho "Iteration: $i"
done
echo
for i in {1..10..2}
doecho "Iteration: $i"
done
echo
# 使用while循环,循环直到条件为假
i=1
while [ $i -le 5 ]
doecho "Iteration: $i"((i++))  # 递增
done
echo
# 使用while循环直到用户输入 'quit'
while true
doread -p "Enter a command (type 'quit' to exit): " commandif [ "$command" == "quit" ]thenecho "Exiting..."breakfiecho "You entered: $command"
done
echo
# 使用until循环,直到条件为真时才停止
i=1
until [ $i -gt 5 ]
doecho "Iteration: $i"((i++))  # 递增
done
echo
# 使用break提前退出循环
for i in 1 2 3 4 5
doif [ $i -eq 3 ]thenecho "Breaking the loop at i=$i"breakfiecho "Iteration: $i"
done
echo
# 使用continue跳过当前迭代
for i in 1 2 3 4 5
doif [ $i -eq 3 ]thenecho "Skipping the loop at i=$i"continuefiecho "Iteration: $i"
done

运行结果:

 

十、函数定义与调用

在 Shell 脚本中,函数(Function)是一段可重复执行的代码块,主要用于组织结构、提高代码复用性、减少重复编写。

1、函数的定义

Shell 中函数的定义有两种常见写法:

# 写法一(推荐)
function_name() {命令序列
}# 写法二(等价)
function function_name {命令序列
}

2、函数的调用

定义好函数后,只需要使用函数名就可以调用该函数:

hello() {echo "Hello, Shell!"
}# 调用函数
hello

输出:

Hello, Shell!

 3、带参数的函数

Shell 函数可以像脚本一样接收参数,通过 $1, $2... 表示第 1、第 2 个参数,$# 表示参数个数,$* 表示所有参数。

sum() {echo "第一个参数: $1"echo "第二个参数: $2"echo "参数个数: $#"echo "所有参数: $*"
}sum 10 20

输出:

第一个参数: 10
第二个参数: 20
参数个数: 2
所有参数: 10 20

4、函数的返回值

Shell 函数默认的返回值是函数中最后一条命令的返回码(0 表示成功)。你也可以用 return 指定返回 0~255 的整数值,并通过 $? 获取。

add() {return $(($1 + $2))
}add 3 4
result=$?
echo "结果是: $result"

输出:

结果是: 7

⚠️ 注意:return 只能返回整数值,如果你想返回字符串或其他复杂结果,可以通过全局变量或命令替换返回。

5、函数返回字符串的方法(使用命令替换)

greet() {local name=$1echo "Hi, $name!"
}msg=$(greet "Tom")
echo "$msg"

输出:

Hi, Tom!

6、函数作用域

Shell 中变量默认是全局的。为了避免变量冲突,可以使用 local 定义局部变量(只能在函数内部使用)。

demo() {local msg="局部变量"echo "$msg"
}demo
# echo $msg  # 报错,变量已出作用域

完整代码:

#!/bin/bash
hello() {echo "Hello, Shell!"
}# 调用函数
hello
echo
sum() {echo "第一个参数: $1"echo "第二个参数: $2"echo "参数个数: $#"echo "所有参数: $*"
}sum 10 20
echo
add() {return $(($1 + $2))
}add 3 4
result=$?
echo "结果是: $result"
echo
greet() {local name=$1echo "Hi, $name!"
}msg=$(greet "Tom")
echo "$msg"
echo
demo() {local msg="局部变量"echo "$msg"
}demo
# echo $msg  # 报错,变量已出作用域
echo

运行结果:

 

7、小结

特性说明
函数定义function_name() {}function function_name {}
参数获取$1, $2, ..., $#, $*, $@
返回值(整型)return 数值,通过 $? 获取
返回值(字符串)echo 输出 + 命令替换接收
局部变量使用 local 定义

十一、项目实践与总结:开机自启 + 综合示例脚本

在完成了对 Shell 基础语法、命令使用、变量类型、用户输入、流程控制、函数调用等知识的学习后,最后用一个开机自启任务+一个完整综合示例脚本来结束。

开机自启任务(运行 ~/myjob/pi5/yolo.py

如果你有一个 Python 程序希望开机自动执行,比如运行摄像头识别或嵌入式项目中用到的 YOLO 模型,可以使用以下 Shell 脚本和方法实现:

方法一:通过 crontab 实现
crontab -e

添加如下行(表示开机启动执行脚本):

@reboot /bin/bash /home/pi/myjob/pi5/start_yolo.sh

然后你可以编写 start_yolo.sh 脚本如下:

#!/bin/bash
# 开机运行 YOLO 脚本
cd ~/myjob/pi5/
python3 yolo.py > yolo.log 2>&1 &

别忘了给这个脚本添加执行权限:

chmod +x ~/myjob/pi5/start_yolo.sh

综合 Shell 脚本示例:demo_all.sh

#!/bin/bash
# Shell 综合示例脚本# 注释使用
:<<!
这是多行注释
学习 Shell 真开心!
!# 输出与变量
echo "欢迎使用 Shell 脚本教程"
name="Shell达人"
echo "你好,$name"# 函数定义与返回值
sum() {local a=$1local b=$2echo "函数参数:a=$a, b=$b"return $((a + b))
}
sum 3 5
result=$?
echo "sum 函数的返回值是 $result"# 用户输入
read -p "请输入你的年龄:" age
echo "你的年龄是 $age"# 算术运算
x=10
y=3
echo "$x + $y = $((x + y))"
echo "$x * $y = `expr $x \* $y`"# 条件判断
if [[ $age -ge 18 ]]; thenecho "成年人"
elseecho "未成年人"
fi# case 语句
read -p "请输入星期数字 (1-7):" day
case $day in
1) echo "星期一" ;;
2) echo "星期二" ;;
3) echo "星期三" ;;
*) echo "其他" ;;
esac# for 循环
echo "打印 1 到 5 的数字:"
for i in {1..5}; doecho "$i"
done# while 循环
count=0
while [[ $count -lt 3 ]]; doecho "count=$count"((count++))
done# 变量类型与作用域
declare -i score=90
declare -r school="Shell大学"
echo "score=$score, school=$school"# 特殊变量
echo "本脚本名称:$0"
echo "第一个参数:$1"
echo "所有参数:$*"
echo "参数个数:$#"# 结束语
echo "脚本执行完毕,感谢阅读!"
exit 0

 可使用 chmod +x demo_all.sh && ./demo_all.sh 来运行这个脚本


总结

Shell 脚本是 Linux 世界中最重要的自动化工具之一。通过它,可以:

  • 快速执行大量重复命令

  • 控制程序逻辑和流程

  • 构建自动化系统任务

  • 提高系统运维和开发效率

本篇博客从基础语法出发,逐步介绍了 Shell 的常用命令、变量、输入输出、流程控制、函数封装以及开机自启脚本设计等内容,希望你能将所学应用到实际项目中,写出属于你自己的自动化脚本工具!

参考:

https://www.bilibili.com/video/BV17T4y1F7WV?vd_source=98bed58398f58cc195df30c92a236213


http://www.mrgr.cn/news/100260.html

相关文章:

  • QT窗口相关控件及其属性
  • 再来1章linux 系列-11 系统的延迟任务及定时任务 ,名单,at ,crontab,mail;/etc/at.allow,/etc/at.deny
  • 使用spring boot vue 上传mp4转码为dash并播放
  • 【深度强化学习 DRL 快速实践】深度确定性策略梯度算法 (DDPG)
  • 【深度强化学习 DRL 快速实践】近端策略优化 (PPO)
  • 【FreeRTOS】事件标志组
  • C语言实现对哈希表的操作:创建哈希表与扩容哈希表
  • Mysql日志undo redo binlog relaylog与更新一条数据的执行过程详解
  • 软考中级-软件设计师 知识点速过1(手写笔记)
  • 大模型应用开发之LLM入门
  • 计算机组成原理-408考点-数的表示
  • 正则表达式三剑客之——awk命令
  • 大内存生产环境tomcat-jvm配置实践
  • RocketMQ 主题与队列的协同作用解析(既然队列存储在不同的集群中,那要主题有什么用呢?)---管理命令、配置安装(主题、消息、队列与 Broker 的关系解析)
  • 张 LLM提示词拓展16中方式,提示词
  • 14-DevOps-快速部署Kubernetes
  • 【2025 最新前沿 MCP 教程 01】模型上下文协议:AI 领域的 USB-C
  • YOLO12架构优化——引入多维协作注意力机制(MCAM)抑制背景干扰,强化多尺度与小目标检测性能
  • 【数据可视化-25】时尚零售销售数据集的机器学习可视化分析
  • 【深度强化学习 DRL 快速实践】异步优势演员评论员算法 (A3C)