Linux - 11 Shell(脚本、变量、条件判断)

news/2025/11/9 21:51:56/文章来源:https://www.cnblogs.com/tangge/p/19205367

Linux Shell 是操作系统的命令行界面(CLI),也是用户与内核交互的桥梁 —— 用户输入命令后,Shell 解析并执行,最终将结果返回。它不仅是执行单个命令的工具,更是强大的脚本语言环境,可自动化重复任务、批量处理数据等。

1)Shell 脚本

1. 脚本入门:第一个 Shell 脚本

规定

#!/bin/bash  # 声明脚本解释器(必须放在第一行)

步骤 1:创建脚本文件

touch hello.sh  # 创建脚本文件

步骤 2:编写脚本内容(用 vim 编辑)

vim hello.sh

输入以下内容:

#!/bin/bash  # 声明脚本解释器(必须放在第一行)
# 这是注释(#开头的行是注释,不执行)
echo "Hello, Linux Shell!"  # 输出字符串
echo "当前时间:$(date)"     # 执行date命令并输出结果($()表示执行命令)
echo "当前用户:$USER"       # 引用环境变量($+变量名)

步骤 3:添加执行权限(直接运行的情况)

脚本默认没有执行权限,需用 chmod 授权:

chmod +x hello.sh  # +x 表示添加“执行权限”,是给a(所有用户)添加x

步骤 4:运行脚本

第一种(不用赋予脚本x的权限):采用 bash 或者 sh + 脚本的相对路径或绝对路径
[root@node01 scripts]# bash hello.sh
hello,world
当前时间:2025年 11月 08日 星期六 10:26:39 CST
当前用户:root[root@node01 scripts]# sh hello.sh
hello,world
当前时间:2025年 11月 08日 星期六 10:26:50 CST
当前用户:root
第二种(需要执行权限):直接运行
[root@node01 scripts]# ./hello.sh
-bash: ./hello.sh: 权限不够

这时区看步骤3,然后

./hello.sh  # 直接运行(必须加./,表示当前目录下的脚本)

输出结果:

[root@node01 scripts]# ./hello.sh
hello,world
当前时间:2025年 11月 08日 星期六 10:36:34 CST
当前用户:root
第三种,使用 source

与直接运行脚本不同,source 命令不会创建新的子 shell,而是在当前 shell 中直接执行文件内容。

可以把 source 命令想象成"复制粘贴"操作:

  • 普通执行脚本:像是把文件发给别人执行(新开终端)
  • source 命令:像是把文件内容直接粘贴到你当前的终端中执行
[root@node01 scripts]# source hello.sh
hello,world
当前时间:2025年 11月 08日 星期六 10:46:19 CST
当前用户:root

2)变量

1、全局变量

  • 快速查看所有全局变量:envprintenv
  • 查看单个全局变量:echo $变量名printenv 变量名
  • 区分全局与局部:export 列出全局变量,set 列出所有变量;
  • 自定义全局变量:export 变量名=值(临时生效,重启终端失效;永久生效需写入配置文件,如 ~/.bashrc)。

一、查看所有全局变量(含系统 + 用户自定义)

  1. 系统预定义的全局环境变量(如 PATHUSERHOME 等,对所有 Shell 进程和子进程生效);
  2. 用户自定义的全局变量(需通过 export 声明,可被当前 Shell 及后续启动的子进程继承)。

1. env - 查看全局变量

直接列出当前 Shell 中所有 已导出的全局环境变量(不含局部变量),格式简洁,适合快速查看:

env

2. printenv - 查看全局变量,支持单个

功能与 env 几乎一致,支持单独查看某个全局变量(后面加变量名),更灵活:

# 查看所有全局变量
printenv# 查看单个全局变量(推荐用这种方式查特定变量)
printenv PATH  # 查看环境变量 PATH
printenv USER  # 查看当前用户变量

3. export  - 自定义全局变量

列出当前 Shell 中 用户自定义的全局变量 + 系统全局变量,同时会显示变量的导出状态(部分系统会标注 declare -x):

export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"

二、查看单个指定的全局变量

如果知道变量名,直接用以下方式快速查询(无需罗列所有变量):

1. echo $变量名(最常用)

echo $PATH   # 查看环境变量 PATH(命令搜索路径)
echo $HOME   # 查看用户家目录
echo $SHELL  # 查看当前使用的 Shell
echo $MY_GLOBAL_VAR  # 查看自定义全局变量

注意:变量名前必须加 $,否则会直接输出变量名字符串(如 echo PATH 会输出 PATH,而非变量值)。

2. printenv 变量名(更严谨,变量不存在时无输出)

printenv PATH  # 输出 PATH 的值
printenv NO_SUCH_VAR  # 变量不存在时,无任何输出(不会报错)

三、区分:全局变量 vs 局部变量

默认情况下,用户在 Shell 中直接定义的变量是 局部变量(仅当前 Shell 生效,子进程无法继承),需用 export 声明为全局变量:

# 1. 定义局部变量(仅当前 Shell 可用)
local_var="我是局部变量"
echo $local_var  # 输出:我是局部变量# 2. 声明为全局变量(当前 Shell + 子进程可用)
export global_var="我是全局变量"# 3. 验证:子进程中能否访问
bash  # 启动一个新的子 Shell(子进程)
echo $local_var  # 输出空(子进程无法访问局部变量)
echo $global_var  # 输出:我是全局变量(子进程可访问全局变量)
exit  # 退出子 Shell,回到原 Shell

通过 set 命令可以查看 所有变量(全局 + 局部)+ 函数,对比 env/printenv 可区分全局与局部:

set  # 列出所有变量(全局+局部)和函数,输出较多

四、常用系统全局变量(速查)

变量名 功能描述
PATH 命令搜索路径(Shell 会在这些目录中找可执行命令)
HOME 当前用户的家目录(如 root 的家目录是 /root
USER 当前登录的用户名
SHELL 当前使用的 Shell 路径(如 /bin/bash
LANG 系统语言 / 字符编码(如 en_US.UTF-8
PWD 当前工作目录(等同于 pwd 命令的输出)
OLDPWD 上一个工作目录(用 cd - 可切换回去)
LOGNAME 当前登录用户的用户名(与 USER 通常一致)
HOSTNAME 服务器主机名
$SECONDS Shell 启动后经过的秒数(可用于计时)
$RANDOM 生成 0-32767 之间的随机整数

2、自定义变量

自定义变量是用户根据需求手动定义的变量,用于存储脚本/命令中的临时数据(如字符串、数字、路径等),是最常用的变量类型。

核心特性

  • 需用户手动定义(格式:变量名=值);
  • 默认是「局部变量」(仅当前 Shell 生效,子进程不可继承);
  • 可通过 export 声明为「全局变量」;
  • 变量名规则:字母/下划线开头,可包含字母、数字、下划线(区分大小写)。
  • 撤销变量:使用 unset
  • 只读变量,使用 readonly,但是不能使用 unset, exit 退出当前进程就行了

关键用法

1. 定义与使用

# 定义变量(等号前后无空格,值含空格需用引号包裹)
name="Linux"    # 字符串变量
age=100         # 数字变量
file_path="/home/user/file.txt"  # 路径变量# 使用变量($变量名 或 ${变量名},推荐用 ${} 避免歧义)
echo "名称:${name}"       # 输出:名称:Linux
echo "年龄:${age}岁"      # 输出:年龄:100岁
echo "文件路径:${file_path}"  # 输出:文件路径:/home/user/file.txt

2. 局部变量 → 全局变量(export

# 定义局部变量(仅当前 Shell 可用)
local_var="我是局部变量"
echo $local_var  # 输出:我是局部变量# 声明为全局变量(当前 Shell + 子进程可用)
export global_var="我是全局变量"# 验证:子进程中访问
bash  # 启动新的子 Shell(子进程)
echo $local_var  # 输出空(子进程无法访问局部变量)
echo $global_var  # 输出:我是全局变量(子进程可访问)
exit  # 退出子 Shell

3. 变量运算($((...))expr

a=10
b=20
sum=$((a + b))  # 算术运算,支持 +-*/%(取余)
echo "sum:${sum}"  # 输出:sum:30c=$(( (a + b) * 2 ))
echo "c:${c}"  # 输出:c:60

3、特殊变量(Shell 内置,特定功能)

特殊变量是 Shell 内置的「功能型变量」,命名多为单个字符(如 $?$#),专门用于处理命令行参数、命令执行状态、进程 ID 等场景,脚本开发中高频使用。

核心特性

  • 无需定义,Shell 自动赋值;
  • 功能固定,不可修改(如 $? 只能读取,不能手动赋值);
  • 多与脚本参数、命令执行结果相关。

常用特殊变量(脚本开发必备)

变量名 功能描述 适用场景 示例(脚本中)
$0 当前脚本/命令的名称 脚本中获取自身名称 脚本 test.sh 中,echo $0 输出 ./test.sh
$1~$n 脚本/命令的第 1~n 个参数 接收外部传入参数 运行 ./test.sh 张三 20$1=张三$2=20
$# 脚本/命令的参数总数 判断参数是否足够 上述示例中 echo $# 输出 2
$* 所有参数(作为一个整体字符串) 遍历所有参数(整体处理) 上述示例中 echo $* 输出 张三 20
$@ 所有参数(每个参数独立为字符串) 遍历所有参数(逐个处理) 循环 for arg in $@; do echo $arg; done 输出 张三、20
$? 上一条命令的执行状态码(0=成功,非0=失败) 判断命令是否执行成功 ls /tmp; echo $? 输出 0(成功);ls /nonexist; echo $? 输出 2(失败)
$$ 当前 Shell/脚本的进程 ID(PID) 区分进程、生成临时文件名 echo $$ 输出 12345(当前进程 PID)
$! 上一个后台进程的 PID 管理后台进程 nohup ./long.sh &; echo $! 输出后台进程 PID
$- 当前 Shell 的运行选项(如 hB 表示开启的功能) 查看 Shell 状态 echo $- 输出 himBH
$_ 上一条命令的最后一个参数 快速复用参数 echo hello world; echo $_ 输出 world

示例1:脚本中使用特殊变量
创建脚本 param_demo.sh

#!/bin/bash
echo "脚本名:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "参数总数:$#"
echo "所有参数(整体):$*"
echo "所有参数(逐个):$@"
echo "当前脚本 PID:$$"
echo "上一个后台进程 PID:$!"
echo "当前Shell运行状态:$-"
echo "上一条命令最后一个参数:$_" 	# 复用上一条echo,这里是 "当前Shell运行状态:$-"
echo "hello"
echo "上一条命令最后一个参数:$_" 	# 复用上一条echo,这里是 "hello"# 遍历所有参数(推荐用 $@,支持含空格的参数)
echo -e "\n遍历参数:"
for arg in "$@"; doecho "参数:${arg}"
done# 判断上一条命令是否执行成功($?)
echo -e "\n判断遍历是否成功:"
if [ $? -eq 0 ]; thenecho "遍历成功(状态码:$?)"
elseecho "遍历失败(状态码:$?)"
fi

运行脚本并传入参数:

chmod +x param_demo.sh
./param_demo.sh 张三 20 "北京 朝阳"

输出结果:

脚本名:./param_demo.sh		   # $0
第一个参数:张三				# $1
第二个参数:20				 # $2
参数总数:3					 # $#
所有参数(整体):张三 20 北京 朝阳   #$*
所有参数(逐个):张三 20 北京 朝阳   #$@
当前脚本 PID:6842		# $$
上一个后台进程 PID:	  # $!
当前Shell运行状态:hB
上一条命令最后一个参数:当前Shell运行状态:hB	# $_
hello
上一条命令最后一个参数:hello				# $_遍历参数:
参数:张三
参数:20
参数:北京 朝阳判断遍历是否成功:
遍历成功(状态码:0)			# $?

示例2:使用 $0-10`

创建 hello.sh

#!/bin/bash
echo "hello,world"
a=b
b="www"
c=123
echo "当前时间:$(date)"
echo "当前用户:$USER"
echo "当前变量:$a"
echo "当前\$0:$0"
echo "当前\$1:$1"
echo "当前\$2:$2"
echo "当前\$3:$3"
echo "当前\$4:$4"
echo "当前\$5:$5"
echo "当前\$6:$6"
echo "当前\$7:$7"
echo "当前\$8:$8"
echo "当前\$9:$9"
echo "当前\$10:${10}"

运行

[root@node01 scripts]# ./hello.sh 001 20 "aaa 啊"
hello,world
当前时间:2025年 11月 08日 星期六 15:45:36 CST
当前用户:root
当前变量:b
当前$0:./hello.sh
当前$1:001
当前$2:20
当前$3:aaa 啊
当前$4:
当前$5:
当前$6:
当前$7:
当前$8:
当前$9:
当前$10:{10}

4、三类变量核心差异对比

维度 预定义变量 自定义变量 特殊变量
来源 系统/Shell 内置 用户手动定义 Shell 内置
定义方式 无需定义,直接使用 变量名=值(如 a=10 无需定义,Shell 自动赋值
作用 获取系统环境、用户信息 存储临时数据 处理参数、执行状态、PID 等
可修改性 部分可修改(如 $PATH 完全可修改(用户控制) 不可修改(功能固定)
作用范围 多为全局变量 默认局部,可通过 export 全局 随 Shell/脚本进程生效
命名风格 多为大写单词(如 $HOME 自定义(字母/下划线开头) 单个字符(如 $?$#

5、单引号和双引号的区别

在 Shell(如 Bash)中,双引号("")和单引号('')的核心区别是 是否对变量、命令、特殊字符进行「解析/扩展」 —— 单引号是「强引用」(完全原样输出),双引号是「弱引用」(仅保留部分解析能力),具体区别和用法如下:

一、核心区别对比表

特性 单引号('' 双引号(""
变量解析($var ❌ 不解析,原样输出$var ✅ 解析变量,替换为变量值
命令替换($(cmd) ❌ 不解析,原样输出$(cmd) ✅ 解析命令,替换为命令执行结果
转义字符(\ ❌ 仅单引号本身(\')不能转义,其他\原样输出 ✅ 仅解析 5 个特殊转义:\$(保留$)、\"(保留")、\\(保留\)、\n(换行)、\t(制表符),其余\原样输出
通配符(*? ❌ 不解析,原样输出通配符 ❌ 双引号内也不解析通配符(通配符仅在无引号/反引号时生效)
空白字符(空格、回车) ✅ 保留原样(无需额外处理空格) ✅ 保留原样(同样支持空格原样显示)

二、逐个特性详细说明

1. 变量解析(最常用区别)

  • 单引号:会把 $变量名 当作普通字符串,不替换为变量值;
  • 双引号:会识别 $变量名,并替换为变量的实际内容。
name="张三"
echo 'Hello, $name'  # 输出:Hello, $name(单引号不解析$name)
echo "Hello, $name"  # 输出:Hello, 张三(双引号解析$name为变量值)

2. 命令替换($(命令)`命令`

  • 单引号:不执行括号内的命令,原样输出命令字符串;
  • 双引号:会执行括号内的命令,将结果替换到字符串中。
date_cmd=$(date +%Y-%m-%d)  # 变量存储当前日期
echo '今天是 $(date +%Y-%m-%d)'  # 输出:今天是 $(date +%Y-%m-%d)(单引号不执行命令)
echo "今天是 $date_cmd"          # 输出:今天是 2025-11-09(双引号解析变量,间接获取命令结果)
echo "当前目录:$(pwd)"          # 输出:当前目录:/root/scripts(双引号直接解析命令替换)

3. 转义字符(\

  • 单引号:几乎不支持转义,只有单引号本身无法在单引号内直接使用(需用其他方式规避),其他 \ 都会原样显示;
  • 双引号:仅支持 5 个特殊转义(\$\"\\\n\t),用于保留特殊字符或插入控制字符。
# 单引号转义示例
echo '这是\单引号\的\转义'  # 输出:这是\单引号\的\转义(\原样输出)
echo '不能直接用'单引号''   # 报错(单引号内无法直接写')
echo '用'\''拼接单引号'     # 输出:用'拼接单引号(正确写法:单引号关闭+转义' + 重新打开单引号)# 双引号转义示例
price=100
echo "价格:\$price 元"  # 输出:价格:$price 元(\$保留$符号,不解析变量)
echo "换行\n制表符\t演示" # 输出:换行(换行)制表符(制表符)演示(解析\n和\t)
echo "双引号:\"Hello\""  # 输出:双引号:"Hello"(\\"保留双引号)
echo "反斜杠:\\"         # 输出:反斜杠:\(\\保留反斜杠)

4. 空白字符(空格、回车)
两种引号都能保留空白字符的原样,避免被 Shell 当作「参数分隔符」,这是引号的共同作用(无引号时,Shell 会忽略多余空格)。

# 无引号:多余空格被忽略
echo Hello   World  # 输出:Hello World(多个空格合并为一个)# 单引号/双引号:保留所有空格
echo 'Hello   World'  # 输出:Hello   World(保留 3 个空格)
echo "Hello   World"  # 输出:Hello   World(同样保留 3 个空格)

5. 通配符(*? 等)
两种引号内的通配符都会被「禁用」,不会被 Shell 解析为文件匹配模式,仅原样输出。

# 无引号:* 匹配当前目录所有文件
echo *  # 输出:file1.txt file2.sh scripts(当前目录文件/文件夹)# 单引号/双引号:* 原样输出
echo '*'  # 输出:*
echo "*"  # 输出:*

三、常见使用场景总结

用单引号('')的场景:

  • 字符串中包含 $()\ 等特殊字符,且不需要解析(原样输出);
  • 固定文本(如提示语、不含变量/命令的常量)。

示例:

echo '请输入密码(无需替换$变量)'  # 输出:请输入密码(无需替换$变量)
echo '命令格式:ssh user@ip -p 22' # 输出:命令格式:ssh user@ip -p 22(无解析)

用双引号("")的场景:

  • 字符串中包含变量($var)或命令替换($(cmd)),需要解析其值;
  • 字符串中包含空格、换行,需要保留原样;
  • 字符串中需要保留 $"\ 等特殊字符(用转义符 \)。

示例:

user=$(whoami)
echo "当前用户:$user,当前目录:$(pwd)"  # 输出:当前用户:root,当前目录:/root/scripts(解析变量和命令)
echo "文件名:\"my file.txt\""          # 输出:文件名:"my file.txt"(保留双引号和空格)

四、易错点提醒

  1. 单引号内不能直接嵌套单引号:需用 '\'' 拼接(关闭单引号 + 转义单引号 + 重新打开单引号);
  2. 双引号内的通配符不生效:如果需要文件匹配(如 *.txt),不要用双引号包裹;
  3. 反引号 `cmd`$(cmd) 功能一致,但双引号内推荐用 $(cmd)(嵌套更方便)。

一句话总结

  • 单引号:所见即所得,完全不解析任何特殊字符;
  • 双引号:解析变量和命令,保留空格,仅对 5 个特殊字符转义。

根据是否需要「解析变量/命令」选择即可 —— 不需要解析就用单引号,需要解析就用双引号!

3)运算符 $((表达式))

用于整数运算(Bash 原生不支持浮点数,需借助 bc 工具),

常用语法$(( 表达式 ))$[ 表达式 ](推荐前者,兼容性更好)。

a=10
b=3# 基础运算
echo "a + b = $((a + b))"  # 输出:a + b = 13
echo "a * b = $[a * b]"    # 输出:a * b = 30($[] 语法兼容)# 自增自减
echo "a++ = $((a++))"      # 输出:a++ = 10(a 变为11)
echo "++a = $((++a))"      # 输出:++a = 12(a 变为12)# 浮点数运算(需用 bc 工具,scale 指定小数位数)
echo "10 / 3 = $(echo "scale=2; 10 / 3" | bc)"  # 输出:10 / 3 = 3.33

4)条件判断

写法一:[...][[...]]条件组合((...))数值

Shell(以 Bash 为例)的条件判断是脚本编写的核心,用于根据「变量值、文件状态、命令执行结果」等判断逻辑走向(比如 if-else 分支)。核心语法有 3 种:[ ... ](原生语法)、[[ ... ]](Bash 扩展语法,推荐)、(( ... ))(数值判断专用),以下是详细用法(含中文示例,适配新手):

一、核心判断语法对比(先选对语法,避免踩坑)

语法格式 适用场景 优点 注意事项
[ 条件 ] 所有 Shell 兼容(跨平台) 兼容性强,基础场景够用 1. 条件两端必须加空格;2. 变量需加双引号;3. 特殊字符(如 < >)需转义
[[ 条件 ]] Bash 专属(推荐优先用) 支持通配符、&&/`
(( 条件 )) 纯数值判断(比较/运算) 支持 ==/>/< 等算术符号,简洁 仅处理整数,不支持字符串/文件判断

✅ 新手建议:优先用 [[ ... ]](字符串/文件判断)和 (( ... ))(数值判断),语法简洁、少踩坑!

二、最常用的判断场景(附中文示例)

1. 数值判断(比较大小/相等)

(( ... )) 最直观,支持 ==/!=/>/</>=/<= 等符号,无需记 -eq/-gt 等关键字。

常用判断条件

判断逻辑 语法((( ... )) 示例(a=10, b=5)
等于 ((a == b)) ((10 == 5)) → 假
不等于 ((a != b)) ((10 != 5)) → 真
大于 ((a > b)) ((10 > 5)) → 真
小于 ((a < b)) ((10 < 5)) → 假
大于等于 ((a >= b)) ((10 >= 10)) → 真
小于等于 ((a <= b)) ((5 <= 10)) → 真

示例脚本(判断分数等级)

read -p "请输入你的分数(0-100):" score# 数值判断:用 ((...)) 简洁明了
if ((score >= 90 && score <= 100)); thenecho "优秀!"
elif ((score >= 60 && score < 90)); thenecho "及格!"
elseecho "不及格!"
fi

2. 字符串判断(比较内容/长度)

[[ ... ]] 最佳,支持通配符、空格处理,变量必须加双引号(避免空格导致语法错误)。

常用判断条件

判断逻辑 语法([[ ... ]] 示例(str1="张三", str2="李四")
字符串相等 [[ "$str1" == "$str2" ]] [[ "张三" == "李四" ]] → 假
字符串不相等 [[ "$str1" != "$str2" ]] [[ "张三" != "李四" ]] → 真
字符串为空(长度=0) [[ -z "$str" ]] [[ -z "" ]] → 真(空字符串)
字符串非空(长度≠0) [[ -n "$str" ]] [[ -n "张三" ]] → 真
字符串包含子串 [[ "$str" == *"子串"* ]] [[ "张三李四" == *"三"* ]] → 真
字符串以某字符开头 [[ "$str" == "前缀"* ]] [[ "张三" == "张"* ]] → 真
字符串以某字符结尾 [[ "$str" == *"后缀" ]] [[ "张三" == *"三" ]] → 真

示例脚本(验证用户输入)

read -p "请输入用户名(至少3个字符):" usernameif [[ -z "$username" ]]; thenecho "错误:用户名不能为空!"
elif [[ "${#username}" -lt 3 ]]; then  # ${#username} 是获取字符串长度echo "错误:用户名长度不能少于3个字符!"
elif [[ "$username" == *" "*. ]]; then  # 禁止包含空格echo "错误:用户名不能包含空格!"
elseecho "用户名合法:$username"
fi

3. 文件/目录判断(运维常用)

[[ ... ]][ ... ],通过 -f/-d 等关键字判断文件状态,是脚本自动化运维的核心。

常用判断条件

判断逻辑 语法([[ ... ]] 示例
是否为普通文件(非目录) [[ -f "文件路径" ]] [[ -f "/etc/passwd" ]] → 真
是否为目录 [[ -d "目录路径" ]] [[ -d "/home" ]] → 真
文件/目录是否存在 [[ -e "路径" ]] [[ -e "/tmp/test.txt" ]] → 假(若不存在)
文件是否可读写执行 [[ -r "文件" ]](读)/ [[ -w "文件" ]](写)/ [[ -x "文件" ]](执行) [[ -x "/bin/ls" ]] → 真(ls 可执行)
文件是否为空(大小=0) [[ -s "文件" ]] [[ -s "empty.txt" ]] → 假(空文件)

示例脚本(备份文件前判断)

file="/etc/nginx/nginx.conf"  # 要备份的文件
backup_dir="/tmp/backup"      # 备份目录# 1. 判断原文件是否存在且是普通文件
if [[ ! -f "$file" ]]; then  # ! 表示“非”(取反)echo "错误:文件 $file 不存在!"exit 1  # 退出脚本,状态码 1 表示错误
fi# 2. 判断备份目录是否存在,不存在则创建
if [[ ! -d "$backup_dir" ]]; thenecho "备份目录 $backup_dir 不存在,正在创建..."mkdir -p "$backup_dir"  # -p 确保父目录也创建
fi# 3. 执行备份(复制文件到备份目录)
cp "$file" "$backup_dir/nginx.conf.$(date +%Y%m%d)"
echo "备份成功:$backup_dir/nginx.conf.$(date +%Y%m%d)"

4. 命令执行结果判断

判断某个命令是否执行成功(比如 ping 是否通、curl 是否请求成功),核心是利用「命令退出状态码」:

  • 命令执行成功 → 退出状态码 0 → 判断为「真」;
  • 命令执行失败 → 退出状态码非 0 → 判断为「假」。

语法格式

# 格式1:直接写命令(推荐,简洁)
if 命令; then# 命令执行成功的逻辑
fi# 格式2:用 $? (命令执行后的状态码,0=成功)
命令
if (( $? == 0 )); then# 成功逻辑
fi

示例脚本(判断网络是否通畅)

ip="www.baidu.com"# 判断 ping 命令是否执行成功(-c 1 发送1个包,-W 2 超时2秒)
if ping -c 1 -W 2 "$ip" > /dev/null 2>&1; then  # >/dev/null 2>&1 隐藏输出echo "网络通畅:$ip 可访问!"
elseecho "网络异常:$ip 无法访问!"
fi

三、条件组合(与/或/非)

当需要多个条件同时满足(与)、任一满足(或)、取反(非)时,用以下语法:

逻辑关系 [[ ... ]] 语法 [ ... ] 语法 示例(a=10, b=5, str="abc")
与(同时成立) [[ 条件1 && 条件2 ]] [ 条件1 -a 条件2 ] [[ $a -gt $b && -n "$str" ]] → 真
或(任一成立) `[[ 条件1 条件2 ]]`
非(取反) [[ ! 条件 ]] [ ! 条件 ] [[ ! -f "/tmp/test.txt" ]] → 真(文件不存在)

✅ 推荐用 [[ ... ]]&&/||,比 [ ... ]-a/-o 更直观、不易出错!

四、新手必避的 3 个坑

  1. 空格问题[[/[ 后面、]]/] 前面必须加空格!
    ❌ 错误:[[-$a == 10]](无空格)
    ✅ 正确:[[ -$a == 10 ]](有空格)

  2. 变量引号:字符串/文件路径变量必须加双引号!避免变量含空格导致语法错误。
    ❌ 错误:[[ $filename == "test.txt" ]](filename 含空格会报错)
    ✅ 正确:[[ "$filename" == "test.txt" ]]

  3. 特殊字符转义[ ... ]</> 需转义(\</\>),[[ ... ]] 无需转义!
    ❌ 错误:[ $a > $b ]> 被当作重定向)
    ✅ 正确:[ $a \> $b ][[ $a > $b ]]

五、实战示例:完整的条件判断脚本

#!/bin/bash
# 功能:判断文件是否存在,若存在则显示其权限和大小,否则创建文件read -p "请输入文件路径:" file_path# 1. 判断输入是否为空
if [[ -z "$file_path" ]]; thenecho "错误:文件路径不能为空!"exit 1
fi# 2. 判断文件是否存在
if [[ -f "$file_path" ]]; thenecho "文件 $file_path 已存在:"echo "权限:$(ls -l "$file_path" | awk '{print $1}')"  # 提取权限echo "大小:$(du -sh "$file_path" | awk '{print $1}')"  # 提取大小
elseecho "文件 $file_path 不存在,正在创建..."touch "$file_path"  # 创建文件if (( $? == 0 )); then  # 判断 touch 命令是否成功echo "文件创建成功!"elseecho "错误:文件创建失败(可能权限不足)!"fi
fi

运行脚本后,输入文件路径(如 /tmp/test.txt),会根据文件是否存在执行不同逻辑,完美覆盖「字符串判断、文件判断、命令结果判断」!

写法二:test 原始判断命令

test 是 Shell 中最原始的条件判断命令,核心作用和 [ ... ] 完全等价([ 本质就是 test 命令的符号链接),用于判断「数值、字符串、文件状态」是否满足条件,语法简单直接,适合快速验证或兼容老脚本。

一、核心用法(3种等价写法)
test 的语法非常固定,三种写法效果完全一致,选一种习惯的即可:

# 写法1:直接用 test 命令(最直观)
test 条件# 写法2:用 [ ] 包裹(最常用,本质是 test 的简写)
[ 条件 ]# 写法3:用 [[ ]] 包裹(Bash 扩展,兼容 test 的所有条件,更强大)
[[ 条件 ]]

✅ 关键提醒:[ 条件 ] 中,[ 后面和 ] 前面必须加空格,否则报错!

二、test 能判断什么?(3大核心场景)
test 的判断逻辑和之前讲的条件判断一致,只是通过「命令参数」表达条件,常用场景如下(附示例):

1. 数值判断(比较整数)
-eq(等于)、-gt(大于)等参数,语法:test 数值1 比较参数 数值2

判断逻辑 test 参数 示例(a=10, b=5) 结果
等于 -eq test $a -eq $b 假(10≠5)
不等于 -ne test $a -ne $b 真(10≠5)
大于 -gt test $a -gt $b 真(10>5)
小于 -lt test $a -lt $b 假(10<5)
大于等于 -ge test $a -ge 10 真(10≥10)
小于等于 -le test $b -le 5 真(5≤5)

示例:

a=10
if test $a -gt 8; thenecho "$a 大于 8"  # 输出:10 大于 8
fi

2. 字符串判断(比较内容/长度)
=(相等)、-z(空字符串)等参数,语法:test "字符串1" 参数 "字符串2"

判断逻辑 test 参数 示例(str1="abc", str2="def") 结果
字符串相等 === test "$str1" = "$str2" 假(abc≠def)
字符串不相等 != test "$str1" != "$str2" 真(abc≠def)
字符串为空 -z test -z "" 真(空字符串)
字符串非空 -n test -n "$str1" 真(abc非空)

示例:

username="root"
if test -n "$username" && test "$username" = "root"; thenecho "当前是管理员用户"  # 输出:当前是管理员用户
fi

3. 文件/目录判断(运维常用)

-f(普通文件)、-d(目录)等参数,语法:test 参数 "文件路径"

判断逻辑 test 参数 示例 结果
是否为普通文件(非目录) -f test -f "/etc/passwd" 真(是文件)
是否为目录 -d test -d "/home" 真(是目录)
文件/目录是否存在 -e test -e "/tmp/test.txt" 假(不存在)
文件是否可执行 -x test -x "/bin/ls" 真(ls可执行)

示例:

file="/tmp/test.txt"
if test -f "$file"; thenecho "文件已存在"
elseecho "文件不存在,创建中..."touch "$file"  # 创建文件
fi

三、条件组合(与/或/非)
test 本身不支持 &&/|| 直接写在命令内,需用 Shell 的逻辑运算符组合多个 test 命令:

逻辑关系 语法 示例(a=10, b=5) 结果
与(同时成立) test 条件1 && test 条件2 test $a -gt $b && test $a -lt 20
或(任一成立) `test 条件1 test 条件2`
非(取反) ! test 条件 ! test -f "/tmp/xxx.txt" 真(文件不存在)

示例:

# 判断文件存在且可写
file="/tmp/test.txt"
if test -f "$file" && test -w "$file"; thenecho "文件可写入"
elseecho "文件不存在或无写入权限"
fi

四、test 和 [ ] / [[ ]] 的关系(关键理解)

  1. [ 条件 ] 就是 test 条件 的简写,比如 [ $a -gt $b ] 等价于 test $a -gt $b,所以两者的条件参数完全一致;
  2. [[ 条件 ]] 是 Bash 对 test/[ ] 的增强版,支持 &&/|| 直接写在内部、支持通配符,更简洁(比如 [[ $a -gt $b && $b -lt 20 ]] 无需拆成两个命令);
  3. 兼容性:test[ ] 兼容所有 Shell(如 sh、ksh),[[ ]] 仅兼容 Bash。

5)测试运算符 (-n|-z|-r)

这类运算符专门搭配 [[ ... ]]/[ ... ]/test 使用,核心分为「字符串运算符」「文件 / 目录运算符」两大类(数值运算符之前讲过,这里聚焦和 -n 同类型的「状态测试符」),以下是最常用、最实用的汇总(附示例 + 场景):

一、字符串相关运算符(和 -n 最贴近,操作字符串)
专门判断字符串的「长度、相等性、包含关系」等,和 -n 功能互补,日常脚本高频使用:

运算符 含义(核心功能) 示例(str1="abc", str2="def", empty="" 结果
-n "$str" 字符串非空(长度≠0) [[ -n "$str1" ]] → 检测 "abc" 是否非空
-z "$str" 字符串为空(长度=0) [[ -z "$empty" ]] → 检测空字符串
="$str1" "$str2" 字符串相等([[ ]]也可用== [[ "$str1" = "abc" ]] → 检测 str1 是否等于 "abc"
!="$str1" "$str2" 字符串不相等 [[ "$str1" != "$str2" ]] → 检测 "abc" 和 "def" 是否不等
=~ 字符串匹配正则表达式(仅[[ ]]支持) [[ "$str1" =~ ^a ]] → 检测 str1 是否以 "a" 开头
== *"子串"* 字符串包含子串(仅[[ ]]支持) [[ "$str1" == *"b"* ]] → 检测 str1 是否包含 "b"

实用示例(字符串校验)

username="admin123"
# 1. 非空 + 长度≥6 + 包含数字
if [[ -n "$username" && ${#username} -ge 6 && "$username" =~ [0-9] ]]; thenecho "用户名合法"  # 输出:用户名合法
fi

二、文件/目录相关运算符(运维高频,判断文件状态)
-n 逻辑类似,但操作对象是「文件/目录路径」,用于判断文件是否存在、是否可读写、是文件还是目录等,是自动化脚本的核心:

运算符 含义(核心功能) 示例(文件路径:file="/etc/passwd", dir="/home" 结果
-e "$path" 路径存在(文件/目录均可) [[ -e "$file" ]] → 检测 /etc/passwd 是否存在
-f "$path" 是普通文件(非目录/设备文件) [[ -f "$file" ]] → 检测 /etc/passwd 是否是普通文件
-d "$path" 是目录 [[ -d "$dir" ]] → 检测 /home 是否是目录
-r "$path" 文件可读(当前用户有读权限) [[ -r "$file" ]] → 检测是否能读 /etc/passwd
-w "$path" 文件可写(当前用户有写权限) [[ -w "$file" ]] → 检测是否能写 /etc/passwd(root用户为真,普通用户为假) 视权限而定
-x "$path" 文件可执行(脚本/命令文件) [[ -x "/bin/ls" ]] → 检测 ls 命令是否可执行
-s "$path" 文件非空(大小≠0) [[ -s "$file" ]] → 检测 /etc/passwd 是否有内容
-L "$path" 是符号链接(软链接) [[ -L "/etc/rc.local" ]] → 检测是否是软链接 真(多数系统)
-nt "$path1" "$path2" path1 比 path2 新(修改时间) [[ "$file" -nt "/tmp/test.txt" ]] → 检测 passwd 是否比 test.txt 新 真(test.txt不存在时也为真)
-ot "$path1" "$path2" path1 比 path2 旧(修改时间) [[ "$file" -ot "/tmp/test.txt" ]] → 检测 passwd 是否比 test.txt 旧 假(test.txt不存在时)

实用示例(文件操作前校验)

backup_file="/tmp/backup.tar.gz"
# 1. 文件存在 + 非空 + 可读 → 解压
if [[ -f "$backup_file" && -s "$backup_file" && -r "$backup_file" ]]; thentar -zxf "$backup_file" -C /tmpecho "解压成功"
elseecho "文件不存在/空文件/无读权限"
fi

三、核心总结(快速选型)

  1. -n 同属「状态测试符」,核心是「判断某个对象的状态」(字符串状态/文件状态);
  2. 记准「前缀含义」:-z(zero,空)、-n(not zero,非空)、-f(file,文件)、-d(directory,目录)、-r(read,可读)、-w(write,可写)、-x(execute,可执行);
  3. 使用场景:
    • 校验用户输入、处理字符串 → 用「字符串运算符」;
    • 操作文件/目录(创建、删除、解压、备份)→ 用「文件/目录运算符」;
  4. 必加双引号:变量(尤其是文件路径、含空格的字符串)必须加 "$var",避免空格/特殊字符导致语法错误。

这些运算符是 Shell 条件判断的「基础积木」,搭配 &&/||/! 组合,就能覆盖绝大多数脚本场景(比如校验输入、自动化运维、文件处理等)!

6)条件判断

Shell(以 Bash 为例)的流程控制是脚本的核心,用于控制命令执行的顺序(顺序、分支、循环),核心分为 4 大类:if-else(分支判断)、for(循环)、while/until(循环)、case(多分支匹配),以下是简洁实用的中文讲解(含示例,适配日常脚本场景):

一、分支控制:根据条件走不同逻辑

1. if-else(条件分支,最常用)

根据条件真假执行不同命令,支持单分支、双分支、多分支。
核心语法

# 单分支(满足条件才执行)
if 条件; then命令1
fi# 双分支(满足/不满足各执行)
if 条件; then命令1  # 条件真
else命令2  # 条件假
fi# 多分支(多个条件递进判断)
if 条件1; then命令1
elif 条件2; then命令2
else命令3  # 所有条件都假
fi

示例:判断文件是否存在

#!/bin/bash
file="/tmp/test.txt"
if [[ -f "$file" ]]; thenecho "文件已存在"
elif [[ -d "$file" ]]; thenecho "这是目录,不是文件"
elseecho "文件不存在,创建中..."touch "$file"
fi

2. case(多值匹配,替代多个 elif)

用于「变量等于多个固定值」的场景(如菜单选择、参数匹配),比 if-elif-else 简洁。
核心语法

case $变量 in值1)命令1;;  # 结束当前分支(必须写)值2|值3)  # 多个值用 | 分隔(或逻辑)命令2;;*)  # 默认分支(所有值都不匹配时执行)命令3;;
esac  # 结束 case(反过来写 case)

示例:简单菜单脚本

echo "请选择操作:1-备份 2-恢复 3-退出"
read choicecase $choice in1)echo "开始备份文件..."# 实际备份命令(如 tar);;2)echo "开始恢复文件..."# 实际恢复命令;;3)echo "退出脚本"exit 0  # 退出脚本;;*)echo "无效选择!只能输入 1/2/3";;
esac

二、循环控制:重复执行命令

1. for 循环(遍历列表/范围,最常用)

适合「已知循环次数」的场景(如遍历文件、数字范围、字符串列表)。
核心语法(3种常用形式)

# 形式1:遍历列表(直接写元素)
for 变量 in 元素1 元素2 元素3; do命令(使用 $变量)
done# 形式2:遍历数字范围(如 1-10)
for 变量 in {起始..结束}; do命令
done# 形式3:遍历文件(如当前目录的 .txt 文件)
for 变量 in 路径通配符; do命令
done#形式4:C 风格 for 循环
for (( 初始值; 循环条件; 变量变化 )); do循环体命令(可使用 $变量 引用当前循环值)
done

示例1:遍历数字(计算 1-10 求和)

sum=0
for i in {1..10}; dosum=$((sum + i))
done
echo "1-10的和:$sum"  # 输出:55# let 方法
sum=0
for i in {1..10}; dolet sum=sum + i  # 等价于 sum=$((sum + i)),let 自动赋值# 简化写法:let sum+=i(复合运算符,更简洁,推荐)# let sum+=i
done
echo "1-10的和:$sum"  # 输出:55

示例2:遍历文件(批量重命名 .txt 文件)

# 把当前目录的所有 .txt 文件改成 .bak(备份)
for file in *.txt; domv "$file" "${file%.txt}.bak"  # 替换后缀
done
[root@node01 scripts]# for file in *.sh;do echo "$file" ;done
for_test.sh
hello.sh
if_test.sh
param_demo.sh

示例3:循环 10 次,输出 1-10

# 循环 10 次,输出 1-10
for ((i=1; i<=10; i++)); doecho "当前数字:$i"
done

2. while 循环(条件为真就循环)

适合「未知循环次数,满足条件继续」的场景(如用户输入正确才退出、等待服务启动)。
核心语法

while 条件; do命令
done

示例1:等待用户输入正确密码

correct_pwd="123456"
read -p "请输入密码:" pwdwhile [[ "$pwd" != "$correct_pwd" ]]; doecho "密码错误!"read -p "重新输入:" pwd
done
echo "密码正确,欢迎使用!"

示例2:读取文件内容(逐行遍历)

# 逐行读取 /etc/passwd 文件
while read -r line; doecho "行内容:$line"
done < /etc/passwd  # < 表示从文件读取输入

3. until 循环(条件为假就循环,反向 while)

while 相反:条件为「假」时继续循环,条件为「真」时退出(用得较少,场景特定)。
核心语法

until 条件; do命令
done

示例:等待网络连通(直到 ping 通百度)

ip="www.baidu.com"
echo "等待 $ip 连通..."until ping -c 1 -W 2 "$ip" > /dev/null 2>&1; dosleep 1  # 每隔1秒试一次
done
echo "$ip 已连通!"

三、循环控制符:改变循环执行流程

在循环中用 break/continue/exit 控制节奏,避免死循环或冗余执行:

控制符 作用 示例场景
break 立即退出当前循环(不再执行后续迭代) 找到目标文件后退出遍历
continue 跳过当前迭代,直接进入下一次循环 跳过空文件,只处理非空文件
exit N 直接退出整个脚本(N 是退出状态码,0=成功) 遇到严重错误时终止脚本

示例:遍历文件时跳过空文件

for file in *.txt; doif [[ -s "$file" ]]; thenecho "处理非空文件:$file"elseecho "跳过空文件:$file"continue  # 跳过当前空文件,进入下一次循环fi
done

示例:找到目标文件后退出循环

target="important.txt"
for file in *.txt; doif [[ "$file" == "$target" ]]; thenecho "找到目标文件:$file"break  # 找到后立即退出循环,不再遍历fi
done

四、实战:完整流程控制脚本(备份文件)

#!/bin/bash
# 功能:批量备份指定目录的 .conf 配置文件到 /tmp/backup# 1. 定义变量
source_dir="/etc"  # 源目录
backup_dir="/tmp/backup"
file_type="*.conf"  # 要备份的文件类型# 2. 检查源目录是否存在
if [[ ! -d "$source_dir" ]]; thenecho "错误:源目录 $source_dir 不存在!"exit 1  # 退出脚本(状态码1表示错误)
fi# 3. 创建备份目录(不存在则创建)
if [[ ! -d "$backup_dir" ]]; thenmkdir -p "$backup_dir"echo "创建备份目录:$backup_dir"
fi# 4. 遍历文件并备份(跳过空文件)
count=0
for file in "$source_dir"/$file_type; do# 跳过不存在的文件(避免通配符不匹配时的无效路径)[[ ! -f "$file" ]] && continue# 跳过空文件if [[ -s "$file" ]]; thencp "$file" "$backup_dir/"echo "备份成功:$file"((count++))  # 计数+1fi
done# 5. 输出结果
if ((count > 0)); thenecho "备份完成!共备份 $count 个文件,路径:$backup_dir"
elseecho "未找到可备份的 $file_type 文件"
fi

五、核心总结(新手必记)

  1. 分支选择:
    • 简单条件 → if-else
    • 多固定值匹配 → case(比 elif 简洁)。
  2. 循环选择:
    • 已知列表/范围 → for(最常用);
    • 条件触发循环 → while
    • 条件不满足才循环 → until(少用)。
  3. 避坑要点:
    • 循环变量加双引号(如 "$file"),避免空格报错;
    • case 每个分支必须以 ;; 结束;
    • read -r 读取文件(保留特殊字符);
    • 避免死循环:确保循环条件最终会变为「假」(如 while 加退出逻辑)。

流程控制的核心是「按场景选对结构」,多练几次上面的示例(求和、备份、菜单),就能熟练应对绝大多数 Shell 脚本场景!

7)let 整数算术运算

在 Shell(Bash)中,let 是专门用于 整数算术运算 的命令,同时支持简单的 逻辑判断(本质是通过算术运算的「退出状态码」实现逻辑判定),核心作用是「执行整数运算+自动赋值」,语法简洁,适合简单的数值计算和逻辑判断场景。

一、核心作用:算术运算 + 自动赋值

let 最基础的用法是替代 $((...)) 进行整数运算,且无需手动赋值(运算结果直接赋给变量),语法比 $((...)) 更简洁。

1. 基础语法

let 表达式  # 表达式中变量无需加 $,直接写变量名
  • 支持的算术运算符:+(加)、-(减)、*(乘)、/(整数除)、%(取余)、++(自增)、--(自减)、**(幂运算,Bash 4.0+);
  • 运算结果直接赋给表达式中的变量(无需 变量=$((...)) 这种写法);
  • 仅支持整数运算,不支持浮点数(浮点数需用 bc 工具)。

2. 基础运算示例

# 1. 简单赋值运算(等价于 a=$((3+5)))
let a=3+5
echo "a = $a"  # 输出:a = 8# 2. 自增/自减(等价于 i=$((i+1)))
i=10
let i++  # 自增(i 变为 11)
echo "i++ = $i"  # 输出:i++ = 11let i--  # 自减(i 变为 10)
echo "i-- = $i"  # 输出:i-- = 10# 3. 复合运算(+=、-=、*= 等)
let b=2
let b*=3  # 等价于 b=$((b*3)) → 2*3=6
echo "b *= 3 → $b"  # 输出:b *= 3 → 6# 4. 幂运算(Bash 4.0+)
let c=2**3  # 2的3次方=8
echo "2**3 = $c"  # 输出:2**3 = 8

二、关键用法:结合逻辑判断(核心关联你的疑问)

let 本身不直接支持 &&/|| 这类逻辑符,但它的 退出状态码 可以当作「逻辑结果」使用:

  • let 运算表达式的 结果为 0 → 退出状态码 1(逻辑「假」);
  • let 运算表达式的 结果非 0 → 退出状态码 0(逻辑「真」);

简单说:let 表达式 执行后,可通过 if 判断其是否「逻辑为真」(本质是判断运算结果是否非 0)。

1. 逻辑判断示例(替代数值比较)

a=10
b=5# 示例1:判断 a > b(等价于 ((a > b)) 或 [ $a -gt $b ])
# 表达式 a - b = 10-5=5(非0)→ 逻辑真
if let "a - b"; then  # 注意:表达式含空格时需加引号echo "a > b"  # 输出:a > b
fi# 示例2:判断 a == b(a - b = 0 → 逻辑假)
if ! let "a - b"; then  # ! 取反(假→真)echo "a != b"  # 输出:a != b
fi# 示例3:结合比较运算符(直接写 ==、>、< 等,需加引号)
if let "a > b && a < 20"; then  # 逻辑与:a>b 且 a<20echo "a 在 (b, 20) 之间"  # 输出:a 在 (b, 20) 之间
fi

2. 逻辑运算的本质(退出状态码)

Shell 中所有命令的执行结果都有「退出状态码」($? 查看,0=成功,非0=失败):

  • let "10-5" → 运算结果 5(非0)→ 退出状态码 0(成功)→ if 判断为「真」;
  • let "10-10" → 运算结果 0 → 退出状态码 1(失败)→ if 判断为「假」;

可以通过 $? 验证:

let "10-5"
echo $?  # 输出:0(结果非0 → 状态码0 → 真)let "10-10"
echo $?  # 输出:1(结果0 → 状态码1 → 假)

三、let 的进阶用法(多表达式、引号规则)

1. 一行执行多个表达式(用逗号 , 分隔)

let x=1, y=x+2, z=y*3  # 依次执行 3 个表达式
echo "x=$x, y=$y, z=$z"  # 输出:x=1, y=3, z=9

2. 引号规则(避免特殊字符解析)

  • 表达式含空格、>/<&&/|| 等特殊字符时,必须加引号(单引号/双引号均可);
  • 表达式无空格时,可省略引号。
# 正确:含空格,加引号
let "a = (10 + 5) * 2"
echo $a  # 输出:30# 正确:含逻辑与 &&,加引号
let "b=3, c=4"
if let "b > 2 && c < 5"; thenecho "b>2 且 c<5"  # 输出:b>2 且 c<5
fi# 错误:含空格未加引号,Shell 会解析为多个参数
# let a = 10 + 5 → 报错(= 前后有空格,未加引号)

四、let 与其他算术方式的区别(怎么选?)

方式 语法示例 核心特点 适用场景
let let a=10+5 简洁,自动赋值,支持逻辑判断 简单整数运算、快速逻辑判断
$((...)) a=$((10+5)) 可嵌套,支持复杂表达式 复杂运算、变量插值(如 echo $((a+b))
expr a=$(expr 10 + 5) POSIX 兼容,需转义 * 兼容老 Shell(如 sh)

选择建议:

  • 简单运算(如自增、加减乘除)→ 用 let(最简洁);
  • 运算结果需直接输出或嵌套表达式 → 用 $((...))
  • 需兼容非 Bash Shell(如 sh)→ 用 expr(少用)。

五、新手必避的坑

  1. 不支持浮点数let a=3.14 会报错,浮点数需用 echo "3.14+2.86" | bc
  2. 变量不加 $let $a=10 错误,必须写 let a=10(表达式中变量直接写名称);
  3. 特殊字符加引号:含空格、>/<&& 等时,必须加引号,否则报错;
  4. 逻辑判断的反向性let 表达式 结果为 0 → 逻辑假,结果非 0 → 逻辑真(别搞反)。

总结

let 是 Shell 中「轻量整数运算工具」,核心功能:

  1. 简化整数运算(自动赋值,比 $((...)) 简洁);
  2. 间接实现逻辑判断(通过退出状态码,替代 ((...)) 进行数值比较);

日常脚本中,若只是简单运算或数值逻辑判断,用 let 更高效;若需复杂表达式或嵌套,优先用 $((...))。记住「结果非0=真,结果0=假」的逻辑规则,就能灵活结合 if 进行条件判断啦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/960765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pythontip 字符串转列表

编写一个程序将字符串转换为字典。 定义函数convert_str_list_to_dict(),参数为str_list(输入的字符串)。 在函数内部,创建一个字典,其中每个字符串使用=进行分割,第一部分为键,第二部分为值。 返回字典。这道题主…

flask: 用click自定义flask的命令

一,安装第三方库 $ pip3 install click 二,代码: import click...@app.cli.command(hellocmd) def hello():"""命令说明:hello命令向你说hello"""click.echo(Update version ...)pri…

arXiv论文管理RAG系统:从零构建生产级AI研究助手

一个完整的生产级RAG系统,能够自动获取arXiv论文、理解内容并回答研究问题。项目涵盖基础设施搭建、PDF处理、混合搜索和LLM集成,适合学习现代AI工程技能。arXiv论文管理RAG系统 一个完整的生产级检索增强生成(RAG)系…

双亲委派模型?就是【Java开发日记】请介绍类加载过程,什么

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

#20232408 2025-2026-1 《网络与系统攻防技术》实验四实验报告 - 20232408

一、实验内容 1.1 实验要求 (1)对恶意代码样本进行识别文件类型、脱壳、字符串提取操作。 (2)使用IDA Pro静态或动态分析所给的exe文件,找到输出成功信息的方法。 (3)分析恶意代码样本并撰写报告,回答问题。 (…

2025.11.10~2025.11.16

周计划 除了当天学习任务之外只搞dp相关练习 提前把练习的内容准备好 模拟赛尽快全部拿到会的分数,只有这一个目标 每天晚上8:30开始总结今天一天的题目收获(做法) 然后补充周计划,NOIP前计划,个人原则 作息规律…

性能学习

1.性能测试理论 01.性能测试理论 02.性能测试指标 03.性能测试流程 2.Jmeter学习 01.jmeter介绍与安装 02.线程组 03.setup线程组 04.tearDown线程组 05.http请求 06.分布式jmeter

实用指南:苹果手机误删照片?别慌,这些找回方法助你找回珍贵回忆

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

前端三剑客——javascript-BOM-DOM-http协议-异步

大纲:1.BOM(浏览器对象模型) window对象 location对象 本地存储2.DOM(文档对象模型)元素操作(直接获取/间接获取)事件操作3.js异步PromiseAsync/await4.HTTP协议URL地址解释HTTP协议概述常见HTTP请求方法请求…

npm: 无法加载文件

在VSCODE终端窗口里运行 编译 TYPESCIPT脚本时(node hello.ts),提示 :npm: 无法加载文件 D:\Program Files\Nodejs\node_global\nmp.ps1, 因为在此系统禁止运行脚本。简单例子: 在VSCODE终端窗口里运行 编译 TYP…

C语言中的算术类型转换

1.寻常算数转换 在C语言中,当不同类型的操作数参与到算术运算时,编译器会将操作数转换成同一类型,再运算。这一过程被称为寻常算术转换,由于这个过程我们程序员看不见,所以它也是一种隐式类型转换(见整型提升) …

OIFHA251108(成都嘉祥)

吐槽 虽然难,但全部都是比较好玩的题目(除了 \(T_1\))。 T1 幸好没做这题(doge)。 其核心思想在于看到有向图以及每条边可以走很多次且只算一次需要很快想到 tarjan,为什么要很快?因为你还要调代码。 然后这是一…

NOIP 模拟赛 4 总结

分数:\(40 + 0 + 0 + 0 = \color{red}{40}\)我恨子任务! 我恨全是坑的贪心! 我很码量超大的数据结构! 我恨 ad-hoc !当然,还是要承认自己很菜,不然分数不可能如此惨淡。 T1 众所周知,贪心本身并不难,难的是这…

2025.11.9——1橙1绿

普及- P14477 图寻中国 Div2月赛T1 普及+/提高 P5687 [CSP-S 2019 江西] 网格图 Kruskal的变形,看了题解才做出来

Python中a = b = 10的底层机制:从名字绑定到引用计数的完整拆解

Python中a = b = 10的底层机制:从名字绑定到引用计数的完整拆解 在Python中,a = b = 10这种“链式赋值”看似是简单的语法糖,但其底层执行逻辑与C语言的同名语法存在本质差异——它不是“先把10赋给b,再把b的值赋给…

Python中“赋值”说法是否规范?与C语言赋值的界限必须划清

Python中“赋值”说法是否规范?与C语言赋值的界限必须划清 在Python语境中,“赋值”是行业内约定俗成的常用说法(如官方文档、教材、社区讨论中频繁出现),但其语义边界必须与C语言的“赋值”严格区分——若直接将…

详细介绍:java-springboot电子商务商品物流跟踪系统 SpringBoot+Java电商订单全程物流可视化平台 基于Java框架的网购商品在途追踪与签收管理系统计算机毕业设计

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Python中“赋值”说法是否规范?详解`=`的语句属性与无返回值特性

Python中“赋值”说法是否规范?详解=的语句属性与无返回值特性 在Python学习中,“赋值”是描述a = 10这类语句的常用说法,但结合之前讨论的“名字-对象绑定模型”“对象三属性(标识、类型、值)”,很多开发者会疑…

CIO修炼之道读书笔记

目录一个目标三层价值提高运营效率(操作层)​加强运营管控(管理层)防范运营风险(决策层)参考资料 CIO修炼之“一三四六” 一个目标 从只关注技术转变为同时关注企业业务和战略,并努力围绕如何让企业更赚钱这个目…

小题狂练 (K)

solset-K\[\]目录 目录[AGC036F] Square Constraints[AGC036F] Square Constraints 容斥钦定一些下界不满足转为只有上界的问题,困难只在求每个界的排名 . 比 \(n\) 小的部分的上界肯定比所有数都大,所以如果知道钦定…