前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何在Bash中编写循环?

如何在Bash中编写循环?

作者头像
用户6543014
发布于 2020-02-21 03:46:36
发布于 2020-02-21 03:46:36
2.6K00
代码可运行
举报
文章被收录于专栏:CU技术社区CU技术社区
运行总次数:0
代码可运行

使用for循环和find命令自动对多个文件执行一组操作。

人们想要学习Unix shell的一个常见原因是释放批处理的功能。如果要对许多文件执行某些操作,一种方法是构造一个遍历这些文件的命令来实现。在编程术语中,这称为执行控制,最常见的示例之一是for循环。

for循环是一个配方,详细说明了您希望计算机对指定的每个数据对象(例如文件)执行什么操作。

经典的循环

Linux终端适用于Linux的7大终端仿真器用于Linux中进行数据分析的10个命令行工具立即下载:SSH备忘单高级Linux命令备忘单Linux命令行教程一个简单的循环是分析文件集合的循环。这本身可能不是一个有用的循环,但它是一种安全的方法,可以向您证明自己有能力分别处理目录中的每个文件。首先,通过创建目录并将一些文件的某些副本放入其中来创建一个简单的测试环境。一开始的时候使用任何文件都可以,但是以后的示例需要图形文件(例如JPEG、PNG或类似文件)。您可以使用文件管理器或在终端中创建文件夹并将文件复制到其中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ mkdir example
        $ cp ~/Pictures/vacation/*.{png,jpg} example

将目录更改为新文件夹,然后列出其中的文件以确认测试环境符合您的期望:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cd example
$ ls -1
cat.jpg
design_maori.png
otago.jpg
waterfall.png

在一个循环中逐个遍历每个文件的语法是:创建一个变量。然后定义您要变量循环通过的数据集。在这种情况下,请使用通配符循环浏览当前目录中的所有文件(通配符匹配所有内容)。然后以分号(;)终止此介绍性子句。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ for f in * ;

根据您的喜好,您可以选择按此处返回。在语法上完成之前,shell不会尝试执行循环。

接下来,定义您希望在每次循环迭代中发生的事情。为简单起见,请使用file命令获取有关每个文件的少量数据,这些数据由f变量表示(但是以$开头,告诉shell将变量的值替换为当前包含的变量):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
do file $f ;

用另一个分号终止子句并关闭循环:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
done

做完了按Return键可启动Shell循环遍历当前目录中的所有内容。for循环将每个文件一个一个地分配给变量f,然后运行命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ for f in * ; do
        > file $f ;
        > done
        cat.jpg: JPEG image data, EXIF standard 2.2
        design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
        otago.jpg: JPEG image data, EXIF standard 2.2
        waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

您也可以这样写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ for f in *; do file $f; done
        cat.jpg: JPEG image data, EXIF standard 2.2
        design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
        otago.jpg: JPEG image data, EXIF standard 2.2
        waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

多行和单行格式对于您的外壳都是相同的,并且产生完全相同的结果。

一个实际的例子

这是一个循环如何对日常计算有用的实际示例。假设您有要发送给朋友的度假照片集。您的照片文件很大,太大而无法通过电子邮件发送,并且不便上传到您的照片共享服务。您想为照片创建较小的网络版本,但是您有100张照片,不想浪费时间一张一张地缩小每张照片。

首先,在Linux,BSD或Mac上使用包管理器安装ImageMagick命令。例如,在Fedora和RHEL上:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ sudo dnf install ImageMagick

UbuntuDebian上:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ sudo apt install ImageMagick

在BSD上,使用端口或pkgsrc。在Mac上,使用Homebrew或MacPorts。

安装ImageMagick后,您将拥有一组用于对照片进行操作的新命令。

为您要创建的文件创建目标目录:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ mkdir tmp

要将每张照片缩小到其原始大小的33%,请尝试以下循环:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ for f in * ; do convert $f -scale 33% tmp/$f ; done

然后在tmp文件夹中查看缩放后的照片。

您可以在循环中使用任意数量的命令,因此,如果您需要对一批文件执行复杂的操作,则可以将整个工作流放在for循环的do和done语句之间。例如,假设您要将每张处理过的照片直接复制到Web主机上的共享照片目录,并从本地系统中删除照片文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ for f in * ; do
    convert $f -scale 33% tmp/$f
    scp -i seth_web tmp/$f seth@example.com:~/public_html
    trash tmp/$f ;
  done

做完了对于for循环处理的每个文件,您的计算机将自动运行三个命令。这意味着,如果您仅以这种方式处理10张照片,则可以为自己节省30条命令,还会节省同样多的时间。

限制循环

并不一定总是要查看每个文件。您可能只想处理示例目录中的JPEG文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ for f in *.jpg ; do convert $f -scale 33% tmp/$f ; done
$ ls -m tmp
cat.jpg, otago.jpg

做完了 ls -m tmpcat.jpg,otago.jpg或者,您可能需要重复执行特定次数的操作,而不是处理文件。for循环的变量由您提供的任何数据定义,因此您可以创建一个循环访问迭代数字而不是文件的循环:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ for n in {0..4}; do echo $n ; done
0
1
2
3
4

更多的循环

您现在已经足够了解创建自己的循环了。在对循环感到满意之前,请在要处理的文件副本上使用它们,并尽可能多地使用带有内置保护措施的命令,以防止您破坏数据并造成不可弥补的错误,例如意外重命名整个文件,相同名称的文件目录,彼此覆盖。

有关高级for循环主题,请继续阅读。

并非所有的shell都是Bash

for关键字内置在Bash shell中。许多相似的shell使用相同的关键字和语法,但是某些shell(例如tcsh)使用不同的关键字(例如foreach)来代替。

在tcsh中,语法本质上相似,但比Bash严格。在以下代码示例中,是否不键入字符串foreach?在第2行和第3行中。它是辅助提示,提醒您仍在构建循环的过程中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ foreach f (*)
foreach? file $f
foreach? end
cat.jpg: JPEG image data, EXIF standard 2.2
design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
otago.jpg: JPEG image data, EXIF standard 2.2
waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

在tcsh中,foreach和end都必须单独出现在单独的行中,因此不能像使用Bash和类似的shell那样在一行上创建for循环。

使用find命令执行for循环

从理论上讲,您可能会发现一个不提供for循环函数的shell,或者您可能只是更喜欢使用带有附加功能的其他命令。

find命令是实现for循环功能的另一种方法,因为它提供了几种方法来定义要包含在循环中的文件范围以及并行处理选项。

find命令旨在帮助您在硬盘驱动器上查找文件。它的语法很简单:您提供要搜索的位置的路径,并找到所有文件和目录:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ find .
.
./cat.jpg
./design_maori.png
./otago.jpg
./waterfall.png

你可以通过添加name的一部分来过滤搜索结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ find . -name "*jpg"
./cat.jpg
./otago.jpg

find的优点在于,可以使用-exec标志将找到的每个文件输入到循环中。例如,要仅缩小示例目录中的PNG照片,请执行以下操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ find . -name "*png" -exec convert {} -scale 33% tmp/{} \;
$ ls -m tmp
design_maori.png, waterfall.png

在-exec子句中,括号字符{}代表正在处理的任何项(换句话说,已定位的任何以PNG结尾的文件,一次一个)。-exec子句必须以分号终止,但是Bash通常尝试自行使用分号。使用反斜杠(\;)“转义”分号,以便find知道将分号视为其终止字符。

find命令非常擅长于其功能,有时它可能太好了。例如,如果重复使用它来查找另一个照片处理的PNG文件,则会出现一些错误:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ find . -name "*png" -exec convert {} -flip -flop tmp/{} \;   
convert: unable to open image `tmp/./tmp/design_maori.png':
No such file or directory @ error/blob.c/OpenBlob/2643.
...

似乎find找到了所有的PNG文件-不仅是当前目录(。)中的文件,还包括您之前处理过并放在tmp子目录中的文件。在某些情况下,您可能想要搜索当前目录以及其中的所有其他目录(以及其中的所有目录)。它可以是功能强大的递归处理工具,尤其是在复杂的文件结构中(例如,音乐艺术家的目录中包含充满音乐文件的专辑目录),但是您可以使用-maxdepth选项对其进行限制。

只查找当前目录下的PNG文件(不包括子目录):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ find . -maxdepth 1 -name "*png"

要在当前目录以及其他子目录级别中查找和处理文件,请将最大深度增加1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ find . -maxdepth 2 -name "*png"

它的默认值是进入所有子目录。

小延伸

使用循环的次数越多,节省的时间和精力就越多,可以处理的任务也就越大。您只是一个用户,但是经过深思熟虑的循环,您可以使计算机完成艰苦的工作。

您可以并且应该像对待其他任何命令一样对待循环,以便在需要对多个文件重复执行一个或两个操作时可以将其放在手边。但是,它也是进行认真编程的合法途径,因此,如果您必须对任意数量的文件执行复杂的任务,请抽出一些时间来计划工作流程。如果您可以在一个文件上实现目标,那么将该可重复过程包装在for循环中是相对简单的,并且唯一需要的“编程”是了解变量的工作方式以及足够的组织以将未处理的文件与已处理的文件分开。只需做一些练习,您就可以从一个Linux用户转移到知道如何编写循环的Linux用户!

——The End——

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SACC开源架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
图解LeetCode——437. 路径总和 III
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
爪哇缪斯
2023/09/06
1630
图解LeetCode——437. 路径总和 III
LeetCode437. 路径总和 III
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
MashiroT
2023/02/01
2430
437. 路径总和 III
给定一个二叉树,它的每个结点都存放着一个整数值。 找出路径和等于给定数值的路径总数。 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 cla
编程张无忌
2021/06/21
1790
437. 路径总和 III
【算法题解】 Day30 搜索与回溯
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
sidiot
2023/08/31
1300
【算法题解】 Day30 搜索与回溯
​LeetCode刷题实战437:路径总和 III
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !
程序员小猿
2021/11/15
2890
图解LeetCode——剑指 Offer 34. 二叉树中和为某一值的路径
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。
爪哇缪斯
2023/05/10
1860
图解LeetCode——剑指 Offer 34. 二叉树中和为某一值的路径
搞定大厂算法面试之leetcode精讲21.树
树这种数据结构包括根节点root,左右节点,子树中又有父节点,子节点,兄弟节点,没有子节点的成为叶子节点,树分为二叉树和多叉树
全栈潇晨
2021/12/06
5600
图解LeetCode——652. 寻找重复的子树(难度:中等)
根据题意,我们要找出重复的子树,那么,就需要我们针对给出的树进行遍历,来统计这个树是由哪些子树构成的。所以,基于这种解题思路,我们首先采用深度优先遍历方式,对树中的每个节点进行遍历,每当遍历一个子树的时候,我们就将该子树存储到哈希表中,我们这里采用的是Map<String, Integer>,其中key存储的是前序/后续拼装的树的字符串(每个节点以“/”分割),value存储的是遍历子树过程中,相同子树出现的个数。那么,为了排重,当且仅当出现了第2次的时候,才放入到待返回的变量List<TreeNode> result中。最终,将result作为结果返回即可。具体操作如下图所示:
爪哇缪斯
2023/05/10
1900
图解LeetCode——652. 寻找重复的子树(难度:中等)
二叉树题目合集
用递归法 ,传入左右两棵树的根节点 ,然后比较 left.left == right.left; 以及 left.right ==right.right;
用户11097514
2024/05/30
740
LeetCode通关:连刷三十九道二叉树,刷疯了!
大家好,我是拿输出博客来督促自己刷题的老三,这一节我们来刷二叉树,二叉树相关题目在面试里非常高频,而且在力扣里数量很多,足足有几百道,不要慌,我们一步步来。我的文章很长,你们 收藏一下。
三分恶
2021/09/08
8530
《剑指 Offer(第 2 版)》树部分JavaScript题解
《剑指 Offer(第 2 版)》通行全球的程序员经典面试秘籍。剖析典型的编程面试题,系统整理基础知识、代码质量、解题思路、优化效率和综合能力这 5 个面试要点。
用户8921923
2022/10/24
4180
《剑指 Offer(第 2 版)》树部分JavaScript题解
【leetcode刷题】T135-路径总和 III
https://leetcode-cn.com/problems/path-sum-iii/
木又AI帮
2019/08/08
3910
每日三题-二叉树的最大深度、二叉树中的最大路径和、路径总和III
👨‍💻个人主页: 才疏学浅的木子 🙇‍♂️ 本人也在学习阶段如若发现问题,请告知非常感谢 🙇‍♂️ 📒 本文来自专栏: 算法 🌈 算法类型:Hot100题 🌈 ❤️ 支持我:👍点赞 🌹收藏 🤟关注 每日三题 二叉树的最大深度 二叉树中的最大路径和 路径总和III 补上11月12日的每日三题 二叉树的最大深度 解法一 递归 class Solution { public int maxDepth(TreeNode root) { if(root == nu
才疏学浅的木子
2022/11/18
3180
每日三题-二叉树的最大深度、二叉树中的最大路径和、路径总和III
二叉树刷题总结:二叉树的属性
这就需要去判断根节点下左子树与右子树里侧和外侧是否相等。比较的方法是拿左子树的 “左-右-中” 节点和右子树的“右-左-中”为顺序的节点做比较。
HelloWorld杰少
2022/08/04
3530
二叉树刷题总结:二叉树的属性
​LeetCode刷题实战113:路径总和 II
https://leetcode-cn.com/problems/path-sum-ii/
程序员小猿
2021/01/19
2210
​LeetCode刷题实战113:路径总和 II
前端学数据结构与算法(六):二叉树的四种遍历方式及其应用
上一章我们从0到1的实现了一颗二叉搜索树,以及理解了二叉搜索树的特性与基本操作,这一章介绍关于二叉树的更多操作,也就是树的遍历。主要包括前序遍历、中序遍历、后序遍历、层序遍历,前面三种也叫深度优先遍历(DFS),最后的层序遍历也叫广度优先遍历(BFS),理解这四种遍历方式的不同,再遇到树相关的算法问题时,也就能更加游刃有余。这里不单指二叉搜索树,遍历思想同样适用于多叉树。
飞跃疯人院
2020/10/07
1.1K0
同学,二叉树的各种遍历方式,我都帮你总结了,附有队列堆栈图解(巩固基础,强烈建议收藏)
二叉树(binary tree) 是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。
灵魂画师牧码
2021/02/05
4.6K0
同学,二叉树的各种遍历方式,我都帮你总结了,附有队列堆栈图解(巩固基础,强烈建议收藏)
二叉树各种遍历真的很难?大sai带你拿捏!
很多时候我们需要使用非递归的方式实现二叉树的遍历,非递归枚举相比递归方式的难度要高出一些,效率一般会高一些,并且前中后序枚举的难度呈一个递增的形式,非递归方式的枚举有人停在非递归后序,有人停在非递归中序,有人停在非递归前序(这就有点拉胯了啊兄弟)。
bigsai
2021/10/08
6870
二叉树各种遍历真的很难?大sai带你拿捏!
树的遍历总结
有返回值的递归遍历有两种情况: 1. 要维持一个树的结构,最后返回根节点,即返回值是TreeNode
Tim在路上
2020/08/05
1.7K0
树的遍历总结
路径总和(I、II、III)
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
木子星兮
2020/07/17
1.3K0
推荐阅读
相关推荐
图解LeetCode——437. 路径总和 III
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档