打开网易新闻 查看精彩图片

Linux 上的目录允许您将文件分组到不同的单独集合中。缺点是从一个目录移动到另一个目录来执行重复性任务变得乏味。这是自动化的方法。

所有关于目录

当您被介绍到 Linux 时,您学习的第一个命令可能是,但不会落后太多。了解目录以及如何在它们周围移动,尤其是嵌套的子目录,是了解Linux 如何组织自身以及如何将自己的工作组织到文件、目录和子目录中的基本部分。

ls

cd

掌握目录树的概念——以及如何在它们之间移动——是您在熟悉 Linux 环境时所经历的许多小里程碑之一。与路径一起使用会将您带到该目录。类似或单独的快捷方式将您带回您的主目录,并将您在目录树中向上移动一级。简单的。

cd

cd ~

cd

cd ..

但是,没有一种同样简单的方法可以在目录树的所有目录中运行命令。我们可以通过不同的方式实现该功能,但没有专门用于该目的的标准 Linux 命令。

某些命令,例如,具有强制它们以 递归方式操作的命令行选项,这意味着它们从一个目录开始,并有条不紊地遍历该目录下的整个目录树。对于,它是(递归)选项。

ls

ls

-R

如果您需要使用不支持递归的命令,则必须自己提供递归功能。这是如何做到这一点的。

树命令

该命令不会帮助我们完成手头的任务,但它确实可以很容易地查看目录树的结构。它在终端窗口中绘制树,以便我们可以及时了解构成目录树的目录和子目录,以及它们在树中的相对位置。

tree

您需要安装.

tree

在 Ubuntu 上,您需要输入:

sudo apt 安装树

在 Ubuntu 上安装树

在 Fedora 上,使用:

sudo dnf 安装树

在 Fedora 上安装树

在 Manjaro 上,命令是:

sudo pacman -Sy 树

在 Manjaro 上安装树

不带参数使用会在当前目录下绘制树。

tree

在当前目录中运行树
打开网易新闻 查看精彩图片
在当前目录中运行树

您可以在命令行上传递路径。

tree

树工作

在指定目录上运行树
打开网易新闻 查看精彩图片
在指定目录上运行树

( directories) 选项排除文件并且只显示目录。

树 -d 工作

运行树并且只显示目录
打开网易新闻 查看精彩图片
运行树并且只显示目录

这是获得目录树结构清晰视图的最方便的方法。此处显示的目录树是以下示例中使用的目录树。有五个文本文件和八个目录。

不要将 ls 的输出解析到遍历目录

您的第一个想法可能是,如果可以递归地遍历目录树,为什么不这样做并将输出传递到解析目录并执行某些操作的其他命令?

ls

ls

解析的输出被认为是不好的做法。由于 Linux 能够创建包含各种奇怪字符的文件和目录名称,因此创建通用的、普遍正确的解析器变得非常困难。

ls

您可能永远不会故意创建像这样荒谬的目录名称,但脚本或应用程序中的错误可能会。

奇怪的目录名称
打开网易新闻 查看精彩图片
奇怪的目录名称

解析合法但考虑不周的文件和目录名称很容易出错。我们可以使用其他方法,它们不依赖于解释.

ls

使用查找命令

该命令具有内置的递归功能,它还具有为我们运行命令的能力。这使我们能够构建强大的单线。如果它是您将来可能想要使用的东西,您可以将您的单行代码变成别名或 shell 函数。

find

该命令递归地遍历目录树,查找目录。每次找到目录时,它都会打印出目录的名称并在该目录中重复搜索。完成对一个目录的搜索后,它会退出该目录并在其父目录中继续搜索。

找工作 -type d -execdir echo "In:" {} \;

使用 find 命令递归查找目录
打开网易新闻 查看精彩图片
使用 find 命令递归查找目录

您可以通过列出目录的顺序来查看搜索在树中的进展情况。通过将命令的输出与单行程序的输出进行比较,您将看到如何依次搜索每个目录和子目录,直到找到没有子目录的目录。然后它返回一个级别并在该级别恢复搜索。

tree

find

find

以下是命令的组成方式。

  • 查找:命令。
  • find
  • work:开始搜索的目录。这可以是路径。
  • -type d:我们正在寻找目录。
  • -execdir:我们将在找到的每个目录中执行一个命令。
  • echo “In:” {}:这是命令。我们只是将目录的名称回显到终端窗口。“{}”保存当前目录的名称。
  • : 这是一个用于终止命令的分号。我们需要用反斜杠转义它,这样 Bash 就不会直接解释它。

稍作改动,我们可以让 find 命令返回匹配搜索线索的文件。我们需要包含 -name 选项和搜索线索。在此示例中,我们正在寻找与“*.txt”匹配的文本文件,并将其名称回显到终端窗口。

查找工作 -name "*.txt" -type f -execdir echo "Found:" {} \;

使用 find 命令递归查找文件
打开网易新闻 查看精彩图片
使用 find 命令递归查找文件

搜索文件还是目录取决于您要实现的目标。要在每个目录中运行命令 ,请使用. 要对每个匹配的文件运行命令 ,请使用.

-type d

-type f

此命令计算起始目录和子目录中所有文本文件中的行数。

查找工作 -name "*.txt" -type f -execdir wc -l {} \;

将 find 与 wc 命令一起使用
打开网易新闻 查看精彩图片
将 find 与 wc 命令一起使用

使用脚本遍历目录树

如果您需要遍历脚本中的目录,您可以使用脚本中的命令。如果您需要(或只是想)自己进行递归搜索,您也可以这样做。

find

#!/bin/bash
shopt -s dotglob nullglob
函数递归{
本地 current_dir dir_or_file
对于 $1 中的 current_dir;做
echo "目录命令:" $current_dir
对于 "$current_dir"/* 中的 dir_or_file;
如果 [[ -d $dir_or_file ]]; 然后
递归“$dir_or_file”
别的
wc $dir_or_file

完毕
完毕
}
递归“$ 1”

将文本复制到编辑器中并将其保存为“recurse.sh”,然后使用命令使其可执行。

chmod

chmod +x 递归.sh

使 recurse.sh 脚本可执行

该脚本设置了两个 shell 选项,并且.

dotglob

nullglob

该设置意味着扩展通配符搜索词时将返回以句点“ ”开头的文件和目录名称。这实际上意味着我们在搜索结果中包含隐藏文件和目录。

dotglob

该设置意味着未找到任何结果的搜索模式将被视为空字符串。他们不默认搜索词本身。换句话说,如果我们使用星号通配符“ ”搜索目录中的所有内容,但没有结果,我们将收到空字符串而不是包含星号的字符串。这可以防止脚本无意中尝试打开名为“*”的目录,或将“*”视为文件名。

nullglob

接下来,它定义了一个名为. 这就是有趣的事情发生的地方。

recursive

声明了两个变量,称为和。这些是局部变量,只能在函数内引用。

current_dir

dir_or_file

在函数中也使用了一个被调用的变量。这是调用函数时传递给函数的第一个(也是唯一一个)参数。

$1

该脚本使用两个循环,一个嵌套在另一个内部。第一个(外部)循环用于两件事。

for

for

一种是运行您想要在每个目录中执行的任何命令。我们在这里所做的只是将目录的名称回显到终端窗口。您当然可以使用任何命令或命令序列,或者调用另一个脚本函数。

外部 for 循环所做的第二件事是检查它可以找到的所有文件系统对象——可以是文件也可以是目录。这就是内循环的目的。反过来,每个文件或目录名称都被传递到变量中。

for

dir_or_file

然后在 if 语句中测试该变量以查看它是否是目录。

dir_or_file

  • 如果是,则函数调用自身并将目录名称作为参数传递。
  • 如果变量不是目录,那么它必须是文件。您希望应用于文件的任何命令都可以从语句的子句中调用。您还可以在同一脚本中调用另一个函数。
  • dir_or_file
  • else
  • if

脚本中的最后一行调用该函数并传入第一个 命令行 参数作为要搜索的起始目录。这就是整个过程的开始。

recursive

$1

让我们运行脚本。

./recurse.sh 工作

从最浅到最深处理目录
打开网易新闻 查看精彩图片
从最浅到最深处理目录

遍历目录,脚本中将在每个目录中运行命令的点由“Directory command for:”行指示。找到的文件会在其上运行命令来计算行数、单词和字符数。

wc

处理的第一个目录是“work”,然后是树的每个嵌套目录分支。

需要注意的一个有趣的点是,您可以通过将特定于目录的命令从内部 for 循环的上方移动到其下方来更改目录的处理顺序。

让我们将“Directory command for:”行移到内部循环的后面。

done

for

#!/bin/bash
shopt -s dotglob nullglob
函数递归{
本地 current_dir dir_or_file
对于 $1 中的 current_dir;做
对于 "$current_dir"/* 中的 dir_or_file;
如果 [[ -d $dir_or_file ]]; 然后
递归“$dir_or_file”
别的
wc $dir_or_file

完毕
echo "目录命令:" $current_dir
完毕
}
递归“$ 1”

现在我们将再次运行该脚本。

./recurse.sh 工作

从最深到最浅处理目录
打开网易新闻 查看精彩图片
从最深到最浅处理目录

这一次,这些目录首先从最深的层次应用到它们的命令,备份树的分支。最后处理作为参数传递给脚本的目录。

如果首先处理更深的目录很重要,那么您可以这样做。

递归很奇怪

这就像用自己的电话给自己打电话,给自己留言,告诉自己下次见面的时候——重复。

在您掌握它的好处之前可能需要付出一些努力,但是当您这样做时,您会发现它是一种解决难题的优雅的编程方式。