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

Shell 中 ()、(())、[]、{} 的用法详解

文章目录

  • Shell 中 ()、(())、[]、{} 的用法详解
    • 一、先明确:四类符号的核心功能定位
    • 二、逐个拆解:用法、示例与避坑点
      • 1. `()`:子 Shell 执行,隔离环境
        • 核心用法1:子 Shell 执行命令,隔离变量
        • 核心用法2:`$()` 捕获命令输出(命令替换)
      • 2. `(())`:算术扩展,专注数值计算与比较
        • 核心用法1:整数计算(替代 `expr`)
        • 核心用法2:算术条件判断(替代 `[ ]` 中的 `-gt`/`-lt`)
      • 3. `[]`:条件测试(等价于 `test` 命令)
        • 先明确:`[]` 与 `test` 的等价性
        • 核心用法1:数值比较(需用 `-gt`/`-lt` 等符号)
        • 核心用法2:字符串比较
        • 核心用法3:文件属性判断(常用场景)
        • 避坑点:`[]` 的语法严格性
      • 4. `{}`:变量范围界定 + 代码块
        • 核心用法1:变量范围界定(最常用)
        • 核心用法2:代码块(批量执行命令,不启动子 Shell)
    • 三、总结:四类符号的“场景选择指南”

Shell 中 ()、(())、[]、{} 的用法详解

在 Shell 脚本中,()(())[]{} 是功能差异极大的符号,分别对应“子 Shell 执行”“算术计算”“条件判断”“变量范围界定”等核心场景。本文结合你之前关注的字符串操作和运算符,系统拆解这四类符号的用法,帮你彻底理清适用边界,避免混淆。

一、先明确:四类符号的核心功能定位

首先用一张表区分四类符号的“本质用途”,避免从语法细节陷入混乱:

符号核心功能典型使用场景依赖环境
()启动子 Shell 执行命令,不影响当前 Shell临时执行命令、隔离变量作用域所有 Shell(bash、sh 等)
(())算术扩展,用于数值计算和比较整数运算、算术条件判断(如 a > bBash 专属(不兼容 sh)
[]条件测试(等价于 test 命令)字符串比较、数值比较、文件属性判断所有 Shell
{}1. 变量范围界定;2. 代码块(需加 ;明确变量边界(如 ${var}123)、批量执行命令所有 Shell

二、逐个拆解:用法、示例与避坑点

1. ():子 Shell 执行,隔离环境

() 会启动一个独立的子 Shell 进程,在其中执行括号内的命令,特点是:

  • 子 Shell 中的变量、环境变量修改不影响当前 Shell(隔离作用域);
  • 命令执行结果可通过 $() 捕获(即“命令替换”,等价于反撇号 `)。
核心用法1:子 Shell 执行命令,隔离变量
# 当前 Shell 定义变量 a=10
a=10
echo "当前 Shell 初始 a:$a"  # 输出:当前 Shell 初始 a:10# 用 () 启动子 Shell,修改 a 的值
(a=20; echo "子 Shell 中 a:$a")  # 输出:子 Shell 中 a:20# 回到当前 Shell,查看 a 的值(未被修改)
echo "当前 Shell 最终 a:$a"  # 输出:当前 Shell 最终 a:10

避坑点:若想让子 Shell 的变量影响当前 Shell,需用管道或重定向(如 (a=20; echo $a) > temp.txt,再从文件读取),但直接赋值无效。

核心用法2:$() 捕获命令输出(命令替换)

这是 () 最常用的场景,替代反撇号 ` 实现“执行命令并获取结果”,支持嵌套:

# 场景1:获取当前目录下的文件数(ls 结果通过 wc -l 统计)
file_count=$(ls -l | wc -l)
echo "当前目录文件数:$file_count"# 场景2:嵌套命令替换(先找 python 路径,再查看路径属性)
python_attr=$(ls -l $(which python))
echo "Python 命令属性:$python_attr"

优势:反撇号 ` 不支持嵌套(如 `ls `which python` 报错),而 $() 完全支持,可读性更强。

2. (()):算术扩展,专注数值计算与比较

(()) 是 Bash 专属的“算术扩展”语法,专门处理整数运算和算术条件判断,特点是:

  • 支持所有算术运算符(+-*/% 等),无需转义 *(区别于 expr);
  • 支持算术比较(><>=<===!=);
  • 变量引用可省略 $(如 ((a + b)) 而非 (( $a + $b )))。
核心用法1:整数计算(替代 expr
a=23
b=24# 1. 基础运算:直接计算并输出
echo "a + b = $((a + b))"  # 输出:a + b = 47
echo "a * b = $((a * b))"  # 输出:a * b = 552(无需转义 *)# 2. 运算结果赋值给变量
c=$((a * b + 10))  # 23*24 +10 = 552+10=562
echo "c = $c"  # 输出:c = 562# 3. 自增/自减(类似其他编程语言)
((a++))  # a 自增 1(从23变为24)
echo "a 自增后:$a"  # 输出:a 自增后:24

在这里插入图片描述
在这里插入图片描述

核心用法2:算术条件判断(替代 [ ] 中的 -gt/-lt

if 语句中,(()) 可直接判断数值大小,语法比 [ ] 更简洁(无需记 -gt/-lt 等符号):

age=25
if ((age >= 18 && age <= 30)); thenecho "年龄在 18-30 之间(青年)"  # 输出:年龄在 18-30 之间(青年)
fi# 对比 [ ] 的写法(需用 -ge/-le 和 -a)
if [ $age -ge 18 -a $age -le 30 ]; thenecho "年龄在 18-30 之间(青年)"
fi

避坑点(()) 仅支持整数,不支持小数(如 ((3.14 > 3)) 会报错);且不支持字符串比较(如 (( "a" == "b" )) 报错)。

在这里插入图片描述

3. []:条件测试(等价于 test 命令)

[]test 命令的简写形式,核心功能是条件测试,包括“字符串比较”“数值比较”“文件属性判断”三类场景,返回值为“0(成立)”或“非0(不成立)”,需结合 if/&&/|| 使用。

先明确:[]test 的等价性
# 以下两条命令完全等价(判断文件 /etc/passwd 是否存在)
test -f /etc/passwd && echo "文件存在"
[ -f /etc/passwd ] && echo "文件存在"  # 更常用的写法
核心用法1:数值比较(需用 -gt/-lt 等符号)

[] 中不能直接用 >/<(会被当作重定向符号),必须用专用的数值比较运算符:

运算符含义示例(判断 a=23,b=24)
-eq等于[ $a -eq $b ] → 不成立(23≠24)
-ne不等于[ $a -ne $b ] → 成立(23≠24)
-gt大于[ $a -gt $b ] → 不成立(23<24)
-lt小于[ $a -lt $b ] → 成立(23<24)
-ge大于等于[ $a -ge $b ] → 不成立
-le小于等于[ $a -le $b ] → 成立

示例:

a=23
b=24
if [ $a -lt $b ]; thenecho "$a 小于 $b"  # 输出:23 小于 24
fi
核心用法2:字符串比较

[] 中字符串比较需注意“是否加双引号”(避免空值导致语法错误):

运算符含义示例(str1=“abc”,str2=“abd”)
==/=等于[ "$str1" == "$str2" ] → 不成立
!=不等于[ "$str1" != "$str2" ] → 成立
-z字符串长度为0(空)[ -z "$str1" ] → 不成立(str1非空)
-n字符串长度非0(非空)[ -n "$str1" ] → 成立(str1非空)

示例:

username="admin"
# 判断用户名是否为 admin(加双引号避免 username 为空时报错)
if [ "$username" == "admin" ]; thenecho "欢迎管理员登录"  # 输出:欢迎管理员登录
fi# 判断字符串是否为空
empty_str=""
if [ -z "$empty_str" ]; thenecho "empty_str 是空字符串"  # 输出:empty_str 是空字符串
fi
核心用法3:文件属性判断(常用场景)

[] 支持判断文件是否存在、是否为目录/普通文件等,是脚本中“文件操作前校验”的核心语法:

运算符含义示例(判断 /etc/passwd)
-f是否为普通文件[ -f /etc/passwd ] → 成立(是普通文件)
-d是否为目录[ -d /etc/passwd ] → 不成立(非目录)
-e文件/目录是否存在[ -e /etc/passwd ] → 成立(存在)
-r是否有读权限[ -r /etc/passwd ] → 成立(root有读权限)
-w是否有写权限[ -w /etc/passwd ] → 成立(root有写权限)
-x是否有执行权限[ -x /etc/passwd ] → 不成立(无执行权限)

示例:

file="/etc/passwd"
if [ -f "$file" ] && [ -r "$file" ]; thenecho "$file 是普通文件且有读权限"  # 输出:/etc/passwd 是普通文件且有读权限
fi
避坑点:[] 的语法严格性
  • 括号内前后必须有空格(如 [ -f /etc/passwd ] 正确,[-f /etc/passwd] 报错);
  • 变量必须加双引号(如 [ "$username" == "admin" ],避免变量为空时变成 [ == "admin" ] 语法错误);
  • 不能直接用 &&/||(需用 -a/-o 表示“与”/“或”,如 [ -f "$file" -a -r "$file" ])。

4. {}:变量范围界定 + 代码块

{} 在 Shell 中有两种核心用法,需根据场景区分:

核心用法1:变量范围界定(最常用)

当变量名后紧跟其他字符(如数字、字母)时,用 {} 明确变量边界,避免 Shell 误判变量名:

product="Python"
# 需求:输出 "Python3.11"(变量 product 后紧跟 3.11)
# 错误:Shell 会把 $product3.11 当作一个变量(未定义,输出空)
echo "$product3.11"  # 输出:(空值)# 正确:用 {} 明确变量是 product,后续 3.11 是普通字符
echo "${product}3.11"  # 输出:Python3.11

延伸:结合字符串操作(你之前关注的内容),${} 还支持“子串提取”“长度计算”:

str="this is zjl"
echo "${#str}"        # 计算长度:输出 10
echo "${str:5:2}"     # 提取子串:从索引5开始取2个字符,输出 "is"
核心用法2:代码块(批量执行命令,不启动子 Shell)

{} 可包裹多个命令,作为“代码块”执行,特点是:

  • 不启动子 Shell,命令在当前 Shell 执行(变量修改会影响当前 Shell);
  • 语法严格:括号内最后一条命令必须加 ;,且 { 后必须有空格。

示例:

# 用 {} 执行代码块,修改当前 Shell 的变量
a=10
{a=20echo "代码块中 a:$a"  # 输出:代码块中 a:20b=30  # 定义变量 b,在当前 Shell 生效
}  # 注意:若代码块在一行,需写成 { a=20; echo $a; }# 回到当前 Shell,查看变量(a 和 b 都被修改/定义)
echo "当前 Shell a:$a"  # 输出:当前 Shell a:20
echo "当前 Shell b:$b"  # 输出:当前 Shell b:30

对比 ()() 启动子 Shell,变量修改不影响当前;{} 不启动子 Shell,变量修改影响当前——这是两者作为代码块的核心区别。

三、总结:四类符号的“场景选择指南”

最后用一张表帮你快速决策“什么场景用什么符号”,避免再混淆:

需求场景推荐符号示例
临时执行命令,隔离变量()(a=20; echo $a)(a 不影响当前 Shell)
捕获命令输出(命令替换)$()`file_count=$(ls -l
整数计算/算术比较(())if ((age >= 18)); then ...
条件测试(字符串/数值/文件)[][ -f /etc/passwd ][ "$str" == "abc" ]
明确变量边界/字符串操作${}${product}3.11${#str}
批量执行命令,影响当前 Shell{}{ a=20; echo $a; }(a 影响当前 Shell)

掌握这四类符号后,你可以更灵活地处理 Shell 脚本中的“环境隔离”“数值计算”“条件判断”和“变量操作”,结合之前的字符串和运算符知识,就能写出逻辑清晰、不易出错的脚本了。

http://www.dtcms.com/a/356937.html

相关文章:

  • X-anylabeling3.2标注工具的安装与使用
  • Python五天极限复习
  • 突破传统企业组网瓶颈:某科技公司智能组网服务项目深度解析
  • STL容器的连续性及其访问:vector和deque
  • 刷题日记0829
  • 机器学习算法全景解析:从理论到实践
  • idea控制台从properties中取值然后打印出现控制台乱码问题
  • 2025年热门职业资格证书分析
  • 使用生成对抗网络增强网络入侵检测性能
  • 哈希算法完全解析:从原理到实战
  • AutoDL算力云上传文件太慢了如何解决?
  • 生产环境Spark Structured Streaming实时数据处理应用实践分享
  • 【3D入门-指标篇下】 3D重建评估指标对比-附实现代码
  • SwiGLU激活函数的原理
  • 【原版系统】Windows 11 LTSC 2024
  • Blender中旋转与翻转纹理的实用方法教学
  • Java全栈工程师的面试实战:从技术细节到业务场景
  • 企业级数据库管理实战(三):数据库性能监控与调优的实战方法
  • 达梦数据库-数据缓冲区
  • React前端开发_Day5
  • OCELOT 2023:细胞 - 组织相互作用场景下的细胞检测挑战赛|文献速递-深度学习人工智能医疗图像
  • BSS138-7-F 电子元器件Diodes美台N沟道小信号增强型MOSFET晶体管
  • 基于MCP工具的开发-部署-上线与维护全流程技术实现与应用研究
  • Bert学习笔记
  • CSS scale函数详解
  • 基于BeautifulSoup库的简易爬虫实现:以大学排名为例
  • 【K8s】整体认识K8s之与集群外部访问--service
  • 机器学习回顾——逻辑回归
  • pcl封装6 connection_cloud 提取聚簇后的每个点云
  • 开源vs商用美颜sdk:美白滤镜功能在直播中的优劣对比