Bash Shell脚本学习——唇读数据集格式修复脚本

文章目录

  • 【1】脚本目的
  • 【2】脚本内容
  • 【3】逐句语法分析
    • [(1)`find "DATA_PATH" -name "\\\*.pkl" -type f \| head -20\`](#(1)`find "DATA_PATH" -name "*.pkl" -type f | head -20`)
    • [(2)`find "DATA_PATH" -name "\\\*.pkl" -type f \| wc -l\`](#(2)`find "DATA_PATH" -name "*.pkl" -type f | wc -l`)
    • [(3)`head -1 label_sorted.txt | od -c | head -3`](#(3)head -1 label_sorted.txt | od -c | head -3)
    • [(4)`head -1 label_sorted.txt | grep -P '\r' && echo "发现\\r字符"`](#(4)head -1 label_sorted.txt | grep -P '\r' && echo "发现\\r字符")
    • [(5)`head -1 label_sorted.txt | grep -P '\r' && echo "发现\\r字符"`](#(5)head -1 label_sorted.txt | grep -P '\r' && echo "发现\\r字符")
    • [(6)`cp label_sorted.txt label_sorted.txt.bak`](#(6)cp label_sorted.txt label_sorted.txt.bak)
    • [(7)`cat label_sorted.txt | tr -d '\r' > label_sorted.txt.new`](#(7)cat label_sorted.txt | tr -d '\r' > label_sorted.txt.new)
    • [(8)`mv label_sorted.txt.new label_sorted.txt`](#(8)mv label_sorted.txt.new label_sorted.txt)
    • [(9)`while read -r label; do`](#(9)while read -r label; do)
    • [(10)`TOTAL=((TOTAL + 1))\`](#(10)`TOTAL=((TOTAL + 1))`)
    • [(11)`[ "TRAIN" -gt 0 \] \&\& \[ "VAL" -gt 0 ] && WITH_DATA=((WITH_DATA + 1))\`](#(11)`[ "TRAIN" -gt 0 ] && [ "VAL" -gt 0 ] && WITH_DATA=((WITH_DATA + 1))`)
  • 【4】脚本中的知识点总结

【1】脚本目的

在部署唇读识别项目时,我遇到了一个奇怪的现象:数据集明明完整存在,但训练脚本却报告所有标签的train和val数据都是0!经过系统排查,最终发现罪魁祸首竟然是------Windows换行符

【2】脚本内容

python 复制代码
#(2)确认数据文件存在
# 查找所有pkl文件
find "$DATA_PATH" -name "*.pkl" -type f | head -20  # 前20个pkl文件
find "$DATA_PATH" -name "*.pkl" -type f | wc -l  # pkl文件总数

#(3)检查标签格式
# 检查第一个标签的格式
head -1 label_sorted.txt | od -c | head -3  # 查看不可见字符
head -1 label_sorted.txt | grep -P '\r' && echo "发现\\r字符"  # 检查Windows换行符

#(4)修复步骤
cp label_sorted.txt label_sorted.txt.bak  # 备份
cat label_sorted.txt | tr -d '\r' > label_sorted.txt.new  
mv label_sorted.txt.new label_sorted.txt  # 替换原文件
echo "验证修复后的数据情况:"
TOTAL=0
WITH_DATA=0

while read -r label; do
    [ -z "$label" ] && continue
    TOTAL=$((TOTAL + 1))
    TRAIN=$(find "$DATA_PATH/$label/train" -name "*.pkl" 2>/dev/null | wc -l)
    VAL=$(find "$DATA_PATH/$label/val" -name "*.pkl" 2>/dev/null | wc -l)
    [ "$TRAIN" -gt 0 ] && [ "$VAL" -gt 0 ] && WITH_DATA=$((WITH_DATA + 1))
done < label_sorted.txt

echo "标签总数: $TOTAL"
echo "有完整数据的标签: $WITH_DATA"

【3】逐句语法分析

(1)find "$DATA_PATH" -name "\*.pkl" -type f | head -20

  • 命令: 文件查找与结果限制。

  • 语法:

    bash 复制代码
    DATA_PATH="/home/liyana/my dataset/"

    引号告诉Shell:"/home/liyana/my dataset/" 是一个完整的字符串 ;变量 DATA_PATH 存储的值是:/home/liyana/my dataset/不包含引号

    • find 路径: 在指定路径下递归搜索文件和目录。

    • -name "模式": 按文件名匹配,* 为通配符代表任意字符。

    • -type f: 只搜索普通文件(file),排除目录等其他类型。

    • | head -20: 将查找结果通过管道传递给 head,仅显示前20行。

(2)find "$DATA_PATH" -name "\*.pkl" -type f | wc -l

  • 命令: 文件查找与数量统计。
  • 语法 :
    • find "$DATA_PATH" -name "*.pkl" -type f: 查找所有pkl格式的普通文件。
    • | wc -l: 将找到的文件列表 通过管道传递wc -l 统计行数,即文件总数。

(3)head -1 label_sorted.txt | od -c | head -3

  • 命令 : 以ASCII字符形式显示文件内容,可以看到空格、换行符、制表符等不可见字符
  • 语法 :
    • head -1 label_sorted.txt: 提取标签文件的第1行。
    • | od -c: 通过管道将内容传递给 od (o ctal d ump) 命令,-c 参数表示用字符形式显示。
    • | head -3: 仅显示 od 命令输出的前3行,避免信息过多。

(4)head -1 label_sorted.txt | grep -P '\r' && echo "发现\\r字符"

  • 命令 : 专门检查文件中是否包含Windows换行符 (\r\n),这在Linux环境下可能导致解析问题。

  • 语法:

    • head -1 label_sorted.txt: 同样提取第1行。

    • | grep -P '\r': 通过管道用 grep (G lobal R egular E xpression P rint)搜索,-P 启用Perl正则表达式,\r 匹配回车符

    • grep -P超级模式,支持各种高级匹配

      语法 含义 用途
      \r 回车符 检测Windows换行
      \n 换行符 检测Linux换行
      \t 制表符 找到tab字符
      \x{263a} Unicode字符 匹配表情符号等
      \d 数字 等同于 [0-9]
      \s 空白字符 空格、tab、换行等
    • && echo "发现\\r字符": 如果前面的 grep 命令成功找到 \r 字符,则执行 echo 输出提示信息。

(5)head -1 label_sorted.txt | grep -P '\r' && echo "发现\\r字符"

  • 命令: 特定字符检测与条件提示。
  • 语法 :
    • head -1 label_sorted.txt: 同样提取第1行。
    • | grep -P '\r': 通过管道用 grep 搜索,-P 启用Perl正则表达式,\r 匹配回车符
    • && echo "发现\\r字符": 如果前面的 grep 命令成功找到 \r 字符,则执行 echo 输出提示信息。
  • 作用 : 专门检查文件中是否包含Windows换行符 (\r\n),这在Linux环境下可能导致解析问题。

(6)cp label_sorted.txt label_sorted.txt.bak

  • 命令: 文件备份。
  • 语法 :
    • cp: c opy ,复制文件或目录。
    • cp 源文件 目标文件: 复制源文件到目标文件。
    • 如果目标文件已存在,则会被覆盖。

(7)cat label_sorted.txt | tr -d '\r' > label_sorted.txt.new

  • 命令: 读取原标签文件,删除其中所有的Windows回车符,并将"净化"后的内容保存到一个新文件中。
  • 语法 :
    • cat label_sorted.txt: catenate( 串联),读取并输出指定文件的内容。(cat file1.txt file2.txt file3.txt把三个文件串联起来显示)
    • |: 管道,将前一个命令的输出作为后一个命令的输入。
    • tr -d '\r': tr anslate(字符转换/转译 ),-d 参数表示 d elete,删除输入流中所有的 \r (回车符) 字符。
    • > label_sorted.txt.new: 输出重定向,将前面管道处理后的结果写入到新文件 label_sorted.txt.new (会覆盖已存在的文件)。

(8)mv label_sorted.txt.new label_sorted.txt

  • 命令: 用已修复的新文件替换原始文件,完成修复操作。
  • 语法 :
    • mv 源文件 目标文件: m ove,将源文件移动至目标文件。

(9)while read -r label; do

bash 复制代码
while read -r label; do
    # 循环体...
done < label_sorted.txt  # 👈 输入来自这个文件!
  • 命令 : 开始一个循环,逐行读取文件内容,每行内容存入变量 label 中。
  • 语法 :
    • while ...; do ... done: while 循环结构,当条件为真时,重复执行 dodone 之间的代码块。
    • read -r label: read 命令从标准输入读取一行,-r 参数表示 r aw (原始模式,不解释反斜杠转义符),并将读取的内容赋值给变量 label

(10)TOTAL=$((TOTAL + 1))

  • 命令 : 将变量 TOTAL 的值加1,实现标签总数的计数。
  • 语法 :
    • $(( 算术表达式 )): 算术扩展,Shell会计算双括号内表达式的值。
    • 变量无需在表达式内加 $ 符号引用。常见用法:result=$((a + b))

(11)[ "$TRAIN" -gt 0 ] && [ "$VAL" -gt 0 ] && WITH_DATA=$((WITH_DATA + 1))

  • 命令 : 如果当前标签的训练集和验证集文件数量都大于0,则将有效数据计数器 WITH_DATA 加1。

  • 语法:

    • [ "$TRAIN" -gt 0 ]: 条件测试,判断变量 TRAIN 的值是否 g reater than (大于) 0。

    • 当变量包含空格、制表符时,没有引号"$TRAIN"会出问题:

      bash 复制代码
      # 假设 TRAIN 的值是 "5"(正常情况)
      [ $TRAIN -gt 0 ]  # 替换后:[ 5 -gt 0 ] → ✅ 正常
      
      # 假设 TRAIN 的值是 ""(空字符串)
      [ $TRAIN -gt 0 ]  # 替换后:[ -gt 0 ] → ❌ 语法错误!
      
      # 假设 TRAIN 的值是 "5 "(末尾有空格)
      [ $TRAIN -gt 0 ]  # 替换后:[ 5 -gt 0 ] → ❌ 多了一个参数!
    • [ "$VAL" -gt 0 ]: 判断变量 VAL 的值是否大于0。

    • &&: 逻辑"与",连接多个条件/命令。

    • WITH_DATA=$((WITH_DATA + 1)): 算术运算,将变量 WITH_DATA 的值加1。

【4】脚本中的知识点总结

类别 语法要素 记忆技巧
基础命令 cd, echo, ls, head, wc, find, cat, tr, cp, mv, grep, od 记英文原意:cd=换目录 echo=回声 ls=列表 wc=字数统计 cat=串联 tr=转换 cp=复制 mv=移动 grep=全局正则 od=八进制转储
条件测试 [ -z "$var" ] [ $a -eq $b ] [ $a -gt $b ] -z=zero(空吗?) -eq=equal(相等吗?) -gt=greater than(大于吗?)
命令替换 $(命令) "先把命令结果算出来,再放这里" 动态获取数据
算术运算 $((表达式)) 数学计算小助手 内部变量不加$
变量操作 变量=值 $变量 给数据贴标签,用时喊名字
错误处理 2>/dev/null 命令 && 成功操作 错误信息丢黑洞,脚本安静运行 成功才继续的链式操作
文件安全 cp 源 目标 mv 源 目标 先备份再修改
字符处理 tr -d '字符' grep -P '模式' tr=字符转换器 -d=删除 grep -P=超级搜索模式
相关推荐
larance1 小时前
python中的鸭子类型
开发语言·python
丙寅2 小时前
微信小程序反编译遇到 TypeError: _typeof3 is not a function
开发语言·javascript·ecmascript
醇氧2 小时前
MAC 安装openJDK8
java·开发语言
海阔天空在前走2 小时前
JAVA中六种策略模式的实现
java·开发语言·策略模式
青衫码上行2 小时前
【Java Web学习 | 第十篇】JavaScript(4) 对象
java·开发语言·前端·javascript·学习
禁默2 小时前
基于Rust实现爬取 GitHub Trending 热门仓库
开发语言·rust·github
大邳草民2 小时前
深入理解 Python 的属性化方法
开发语言·笔记·python
胎粉仔3 小时前
Swift 初阶 —— Sendable 协议 & data races
开发语言·ios·swift·sendable·并发域·data races
淮北4943 小时前
linux系统学习(10.shell基础)
linux·运维·服务器·学习