本篇继续来学习shell脚本,对上一篇的文件检查与拷贝脚本进行简化修改。

1 功能说明

在Linux系统中,通过一个shell脚本,实现将一个目录中的所有文件(包括子目录中的),拷贝到顶一个指定的目录,要求:

  • 在拷贝前,先检查两个目录中文件是否一样,不一样的才拷贝
  • 执行拷贝时,打印详细的拷贝信息

2 脚本实现

下面分功能模块来讲解脚本。

2.1 源目录与目标目录

这部分和上次的脚本一样,不再详细介绍

2.2 统计源目录的总文件数和总目录数

# 源目录的所有文件
mapfile -t FILES < <(find "$SRC_DIR" -type f)

解释:

  • find "$SRC_DIR" -type f:在 $SRC_DIR 目录及其子目录下查找所有普通文件,并输出它们的路径
  • <(find "$SRC_DIR" -type f):进程替换(process substitution),将 find 命令的输出作为一个临时文件(或管道)提供给其他命令使用
  • mapfile -t FILES < ...:读取文件
    • mapfile 是一个读取文件内容到数组的命令
    • -t 选项表示去除每行末尾的换行符(trim trailing newline)
    • FILES 是要创建的数组变量名
    • < 表示从前面的输入源读取数据

2.3 对比文件是否一样并拷贝

上篇文章,是通过MD5来比较文件是否相同的,会比较耗时,这次通过cmp指令来比较

copyed_count=0
processed_count=0# 递归遍历源目录下所有文件
for src_file in "${FILES[@]}"; do# 计算相对路径rel_path="${src_file#$SRC_DIR/}"dest_file="$DEST_DIR/$rel_path"# 创建目标子目录dest_dir=$(dirname "$dest_file")mkdir -p "$dest_dir"# 比较文件并执行拷贝if [[ ! -f "$dest_file" ]] || ! cmp -s "$src_file" "$dest_file"; then# 执行复制cp -pv "$src_file" "$dest_file" || echo "警告:复制 $rel_path 失败!"echo "copy: $rel_path"(( copyed_count++ ))fi(( processed_count++ ))process=$(( (processed_count * 100 + TOTAL_FILES - 1) / TOTAL_FILES ))printf "\rprocess: [%d/%d] (%d%%)" "$processed_count" "$TOTAL_FILES" "$process"
doneecho -e "\n=== 操作完成,实际需拷贝 $copyed_count 个文件 ==="

2.3.1 遍历每个文件

前面通过mapfile将文件读到了FILES中,然后就可以通过for循环来依次处理文件了

for src_file in "${FILES[@]}"; do#...
done

解释含义:

  • FILES:是数组的名称(在之前的 mapfile 命令中,这个数组被用来存储文件路径)
  • [@]:是数组的扩展标志,作用是展开数组中的所有元素,并且每个元素会被视为一个独立的参数
  • "${FILES[@]}":(带双引号)时,会保留每个元素的原始格式,包括元素中包含的空格

2.3.2 计算路径并创建子目录

从源目录文件的完整路径中提取出相对路径,然后根据目标位置,组成目标文件的路径

# 计算相对路径
rel_path="${src_file#$SRC_DIR/}"
dest_file="$DEST_DIR/$rel_path"# 创建目标子目录
dest_dir=$(dirname "$dest_file")
mkdir -p "$dest_dir"

解释一下:

  • ${变量#模式},从变量值的开头开始匹配 “模式”,并删除最短的匹配部分

    • src_file,存储着文件的完整路径,例如 /home/user/src/docs/readme.txt
    • $SRC_DIR/,作为匹配的前缀模式,例如 /home/user/src/
    • rel_path ,最终得到 docs/readme.txt
  • $DEST_DIR/$rel_path,拼接成目标文件的路径,例如/home/user/src2/docs/readme.txt

  • dirname ,从文件路径中提取其所在的目录部分,例如/home/user/src2/docs

  • mkdir -p "$dest_dir":用于创建目录

    • mkdir:是 “make directory” 的缩写,用于创建新目录的基础命令。
    • -p:是一个常用选项,全称是 “parent”(父目录),作用是递归创建目录
      当需要创建的目录路径中包含不存在的父目录时,-p 会自动创建所有缺失的父目录,而不会报错。
    • "$dest_dir":是要创建的目标目录路径(通常是一个变量),双引号用于处理路径中包含空格或特殊字符的情况

2.3.3 复制文件

# 比较文件并执行拷贝
if [[ ! -f "$dest_file" ]] || ! cmp -s "$src_file" "$dest_file"; then# 执行复制cp -pv "$src_file" "$dest_file" || echo "警告:复制 $rel_path 失败!"echo "copy: $rel_path"(( copyed_count++ ))
fi(( processed_count++ ))
process=$(( (processed_count * 100 + TOTAL_FILES - 1) / TOTAL_FILES ))
printf "\rprocess: [%d/%d] (%d%%)" "$processed_count" "$TOTAL_FILES" "$process"

解释下

  • [[ ! -f "$dest_file" ]] :如果目标文件 $dest_file不存在,则此部分条件为真
    • [[ ... ]] 是 Bash 的高级条件判断语法
    • ! 表示否定
    • -f 是文件测试运算符,用于检查指定路径是否为普通文件
  • ||:逻辑或运算符
  • ! cmp -s "$src_file" "$dest_file"如果源文件 $src_file 与目标文件 $dest_file 内容不同,则此部分条件为真
    • cmp 是用于比较两个文件内容的命令
    • -s:选项表示 “silent”(静默模式),比较结果不同时不输出具体差异,只通过退出状态码表示
      • 若两文件内容完全相同,cmp -s 退出状态码为 0(表示成功)
      • 若内容不同,退出状态码为非 0(表示失败)
    • ! 否定了 cmp -s 的结果

3 完整的脚本

#!/bin/bashSRC_DIR="./curl-8.15.0"   # 源目录路径
DEST_DIR="./curl-8.15.0-test2"  # 目标目录路径# 确保目录路径不以斜杠结尾,避免路径处理问题
SRC_DIR=${SRC_DIR%/}
DEST_DIR=${DEST_DIR%/}# 检查源目录是否存在
if [ ! -d "$SRC_DIR" ]; thenecho "错误:源目录 $SRC_DIR 不存在!"exit 1
fi# 检查目标目录,不存在则创建
if [ ! -d "$DEST_DIR" ]; thenecho "目标目录 $DEST_DIR 不存在,正在创建..."mkdir -p "$DEST_DIR" || { echo "创建目标目录失败!"; exit 1; }
fiecho "源目录: $SRC_DIR"
echo "目标目录: $DEST_DIR"# 统计源目录的总文件数和总目录数
TOTAL_FILES=$(find "$SRC_DIR" -type f | wc -l)
TOTAL_DIRS=$(find "$SRC_DIR" -type d | wc -l)
# 减去源目录本身
TOTAL_DIRS=$((TOTAL_DIRS - 1))echo "源目录总文件数: $TOTAL_FILES"
echo "源目录总目录数: $TOTAL_DIRS"# 源目录的所有文件
mapfile -t FILES < <(find "$SRC_DIR" -type f)copyed_count=0
processed_count=0# 递归遍历源目录下所有文件
for src_file in "${FILES[@]}"; do# 计算相对路径rel_path="${src_file#$SRC_DIR/}"dest_file="$DEST_DIR/$rel_path"# 创建目标子目录dest_dir=$(dirname "$dest_file")mkdir -p "$dest_dir"# 比较文件并执行拷贝if [[ ! -f "$dest_file" ]] || ! cmp -s "$src_file" "$dest_file"; then# 执行复制cp -pv "$src_file" "$dest_file" || echo "警告:复制 $rel_path 失败!"echo "copy: $rel_path"(( copyed_count++ ))fi(( processed_count++ ))process=$(( (processed_count * 100 + TOTAL_FILES - 1) / TOTAL_FILES ))printf "\rprocess: [%d/%d] (%d%%)" "$processed_count" "$TOTAL_FILES" "$process"
doneecho -e "\n=== 操作完成,实际需拷贝 $copyed_count 个文件 ==="

4 测试结果

这里用curl的源码目录进行测试,拷贝一份到curl-8.15.0-test2目录,然后删除一些文件,进行测试:

可以看到有检查到两个目录存在不一样的文件,在确认拷贝后,执行了拷贝。

再次执行脚本,可以看到文件都完全一样了

5 总结

本篇通过一个文件检查与拷贝的实例,介绍了shell脚本的一些语法,并通过实际测试来验证脚本的功能。

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

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

相关文章

DCA1000 AWR1843 环境安装

mmWaveStudio GUI设计用于表征和评估TI Radar器械。mmWaveStudio通过SPI向mmWave设备发送命令来配置和控制mmWave设备。使用DCA 1000 EVM或TSW 1400 EVM板捕获ADC数据&#xff0c;并在Matlab中处理数据&#xff0c;结果显示在GUI中。mmWaveStudio GUI利用C DLL和一组API通过FTD…

机器学习实操项目01——Numpy入门(基本操作、数组形状操作、复制与试图、多种索引技巧、线性代数)

上一章&#xff1a;【从 0 到 1 落地】机器学习实操项目目录&#xff1a;覆盖入门到进阶&#xff0c;大学生就业 / 竞赛必备 下一章&#xff1a; 机器学习核心知识点目录&#xff1a;机器学习核心知识点目录 机器学习实战项目&#xff1a;【从 0 到 1 落地】机器学习实操项目目…

【vscode】如何离线下载vsxi插件,且在无网环境下离线安装插件-2026最新实验教程

文章目录插件市场也可以从APP进入无网环境下安装插件插件市场 https://marketplace.visualstudio.com/vscode 也可以从APP进入 这里以下载python插件为例 选择版本 无网环境下安装插件

vue2 侦听器watch

一、watch 核心作用监测数据变化&#xff1a;当被监听的数据发生改变时&#xff0c;自动执行指定的处理函数处理副作用&#xff1a;适合执行异步操作&#xff08;如接口请求&#xff09;、复杂逻辑处理等 “副作用” 代码二、基础语法&#xff08;3 种写法&#xff09;简单写法…

今天继续学习Linux系统中shell脚本

首先继续上次的内容看一下另一个案例案例&#xff1a;持续检查服务器负载uptime查看负载情况&#xff08;也可以用top命令&#xff09;[rootlocalhost ~]# uptime22:11:26 up 7:05, 3 users, load average: 0.00, 0.00, 0.00#!/bin/bash #Function:持续检查服务器负载,如果负…

Win系统下配置PCL库第一步之下载Visual Studio和Qt 5.15.2(超详细)

之前在上篇文章Win系统下配置PCL库_windows pcl库 下载-CSDN博客中提到配置PCL库的教程是下载Visual Studio和Qt 5.15.2&#xff0c;后续在测试中我发现前面这两步很重要&#xff0c;一般Qt在线下载器选项选不好的话Qt是装的Qt6&#xff0c;在VTK编译的时候Qt6往往需要C17编译&…

openCV3.0 C++ 学习笔记补充(自用 代码+注释)---持续更新 四(91-)

环境&#xff1a;OpenCV3.2.0 VS201791、合并Y方向重叠的轮廓以轮廓的最小垂直外接矩形框的y为依据&#xff0c;合并y重叠的轮廓。数学逻辑&#xff1a;几何合并的数学表达坐标系统&#xff1a;假设矩形由左上角坐标(x, y)和宽高(width, height)定义。合并公式&#xff1a;合并…

numpy数组的升维和降维的方法集锦

为适配计算包对numpy数组的维度要求&#xff0c;对numpy数组进行升维或降维转化&#xff0c;是非常常见的操作。这里尝试通过多种方式对numpy数组进行升维或降维。1 数组升维1.1 np.expand_dims在0维升维&#xff0c;示例如下a np.array([1,2,3,4,5]) np.expand_dims(a, axis0…

介绍 Python Elasticsearch Client 的 ES|QL 查询构建器

作者&#xff1a;来自 Elastic Miguel Grinberg 学习如何使用 ES|QL 查询构建器&#xff0c;这是一个新的 Python Elasticsearch client 功能&#xff0c;可以更轻松地使用熟悉的 Python 语法构建 ES|QL 查询。 想要获得 Elastic 认证吗&#xff1f;快来了解下一期 Elasticsear…

三坐标测量仪:高精度测量内径检测手段及其实际运用

在工业制造领域中&#xff0c;内径尺寸的精准度直接关系到产品的装配性能、运行稳定性乃至使用寿命。传统检测方法如卡尺、内径千分尺等难以满足高精度、复杂结构件的需求。三坐标测量仪技术的出现&#xff0c;打破了这一困境&#xff0c;成为当前工业领域实现高精度内径检测的…

DIPMARK:一种隐蔽、高效且具备鲁棒性的大语言模型水印技术

摘要水印技术为通过在数据中嵌入隐蔽信息来保障数据安全提供了一种很有前景的方法。该领域的一个首要挑战在于&#xff0c;在水印嵌入过程中保持原始数据的分布。我们的研究拓展并优化了现有的水印框架&#xff0c;着重强调了保持分布&#xff08;DiP&#xff09;水印的重要性。…

IMU传感器价格与高精度惯性导航系统供应商分析

本段将对IMU传感器价格及高精度惯性导航系统的市场情况进行概览。IMU传感器作为惯性导航的重要组成部分&#xff0c;其价格水平受到技术、需求和供应商竞争等多重因素的影响。随着无人机、自动驾驶车辆等新兴应用场景的兴起&#xff0c;IMU传感器的市场需求逐渐攀升。这不仅带动…

3-9〔OSCP ◈ 研记〕❘ WEB应用攻击▸利用REST API提权

郑重声明&#xff1a; 本文所有安全知识与技术&#xff0c;仅用于探讨、研究及学习&#xff0c;严禁用于违反国家法律法规的非法活动。对于因不当使用相关内容造成的任何损失或法律责任&#xff0c;本人不承担任何责任。 如需转载&#xff0c;请注明出处且不得用于商业盈利。 …

UE5 基础应用 —— 07 - 角色蓝图 简单使用

目录 一、角色蓝图 1.1 Pawn / Character 1.2 角色基类 1.3 角色基类设置 1.3.1 基础设置 1.3.2 角色移动和相机旋转 1.3.3 角色移动 —— 锁定视角 1.3.4 角色跳跃 1.4 角色派生类设置 1.4.1 添加动画蓝图 一、角色蓝图 1.1 Pawn / Character Pawn / Character 有什…

流畅的Python(二) 丰富的序列

流畅的Python 第二章&#xff1a;丰富的序列 摘要&#xff1a;在日常Python开发中&#xff0c;我们频繁与各种数据结构打交道&#xff0c;其中序列类型&#xff08;如列表、元组、字符串&#xff09;是基石。然而&#xff0c;你是否曾因对它们理解不深&#xff0c;而在性能优化…

嵌入式 - ARM6

一、按键1. 初始化key.c手册C32 - IOMUXC1. 复用功能配置IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B: 低四位&#xff08;0101&#xff09; IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);SION(信号监控)1: 0 //0 DISABLED — Input Path is determined by functionality MUX_…

菊水PBZ电源在蓄电池充放电测试中的应用探讨

通过高速双极性电源PBZ系列进行蓄电池恒流&#xff0c;恒压充电的方法 对于仪器厂商来说&#xff0c;要求“请按照使用说明书使用”是产品的使用方针&#xff0c;或者说是正确用法。但是&#xff0c;作为具有代表性的通用产品&#xff0c;直流电源的实际使用方法可谓五花八门&…

Zephyr嵌入式实时操作系统安装配置

Zephyr简介 Zephyr 是一款由 Linux 基金会 托管的开源实时操作系统(RTOS),专为资源受限的嵌入式设备(从微控制器到小型边缘计算节点)设计,广泛应用于物联网(IoT)、工业自动化、消费电子、医疗设备、汽车电子等领域。其核心优势在于轻量级、高可配置性和对多架构硬件的广…

Linux系统 SELinux 安全管理与故障排查

一、SELinux 安全上下文管理1. SELinux 简介SELinux&#xff08;Security-Enhanced Linux&#xff09;是 Linux 内核的强制访问控制&#xff08;MAC&#xff09;安全子系统&#xff0c;通过基于标签的访问控制实现细粒度权限管理&#xff0c;遵循最小权限原则。SELinux 有三种工…

解密完全二叉树顺序存储之堆结构

前言:各位老铁好&#xff0c;在前面博客中&#xff0c;笔者分享了有关二叉树的博客&#xff0c;在那篇博客中&#xff0c;笔者讲到了完全二叉树的存储结构中有两种存储方式&#xff0c;一种是顺序存储&#xff0c;一种是链式存储&#xff0c;链式存储笔者已经带各位老铁实现过了…