我正在尝试整理我的照片,这些照片由于各种历史原因而分散在我的系统中。为了让我能够开始这项任务,我一直在尝试使用命令行来构建包含一个或多个 jpg 文件的所有目录的列表。我确定我不必担心寻找其他图像文件格式,但我必须允许 jpg 以大写和小写形式出现。
我希望每个目录名称在最终列表中只出现一次。举个例子,如果我有以下目录,每个目录都包含一个或多个 jpg 或 JPG 文件......
~Mike/Pictures
~Mike/Pictures/London/Olympics
~Mike/Pictures/London
~Mike/Pictures/London/Holiday
~Mike/Photos
~Mike/Family History/Swaine
Run Code Online (Sandbox Code Playgroud)
我希望结果与每个目录只列出一次 - 无论它可能包含的图像文件数量如何 - 最好先排序然后写入文件
~Mike/Family History/Swaine
~Mike/Photos
~Mike/Pictures
~Mike/Pictures/London
~Mike/Pictures/London/Holiday
~Mike/Pictures/London/Olympics
Run Code Online (Sandbox Code Playgroud)
我的命令行技能还达不到这个要求!我可以使用许多简单形式的单个命令,但是一旦它们变得复杂和/或必须通过管道传输,事情往往会出错。
假设 JPEG 图像文件具有后缀.jpg
:
find "$HOME" -type f -name '*.jpg' \
-exec sh -c 'for d; do dirname "$d"; done' sh {} + | sort -u -o jpeg_dirs.txt
Run Code Online (Sandbox Code Playgroud)
这取决于您的名称中没有带有换行符的时髦目录名称。
使用 GNU find
:
find "$HOME" -type f -name '*.jpg' -printf '%h\n' | sort -u -o jpeg_dirs.txt
Run Code Online (Sandbox Code Playgroud)
这些find
命令将在您的主目录下查找所有 JPEG 图像并打印找到它们的目录的名称。在sort -u
将目录名称的列表,排序,并删除重复。结果将写入jpeg_dirs.txt
当前目录中的文件。
在 2021 年初(3.3 年后)回顾这一点,我有点畏缩,因为我上面的解决方案虽然本身没有错,但有点倒退。它还对“漂亮的文件名”(没有换行符)做出了明显的假设。
当您使用find
搜索目录时,不要像我上面那样搜索常规文件;实际上搜索目录。一旦我们有了目录,我们就可以查看它们中的每一个,看看它是否是一个文件匹配*.jpg
或*.JPG
(其他文件名后缀很容易添加):
find "$HOME" -type f -name '*.jpg' \
-exec sh -c 'for d; do dirname "$d"; done' sh {} + | sort -u -o jpeg_dirs.txt
Run Code Online (Sandbox Code Playgroud)
这会从您的主目录向下查看每个目录,并尝试扩展每个目录中的通配模式*.@(jpg|JPG)
。这个模式,也可以写成两个独立的模式,*.jpg
and*.JPG
匹配我们正在寻找的所有文件。如果一个名称匹配,我们假设这是一个我们想要输出名称的目录。这将对仅包含具有这些后缀的子目录的目录产生误报。
我们运行内部bash
脚本的 shell 选项允许我们匹配隐藏名称 ( dotglob
),如果它不匹配任何内容,则允许 globbing 模式完全消失而不是保持未扩展 ( nullglob
),并允许我们使用ksh
-inspired 扩展通配模式@(...|...)
。
使用zsh
外壳:
find "$HOME" -type f -name '*.jpg' -printf '%h\n' | sort -u -o jpeg_dirs.txt
Run Code Online (Sandbox Code Playgroud)
这将创建一个数组变量 ,list
该变量具有仅存储唯一元素的属性。它被初始化为扩展文件名通配模式的结果。该模式匹配主目录中或以下的所有 JPEG 图像文件,:h
最后从生成的路径名中删除实际文件名。在.
使图案只匹配常规文件,并且D
和N
行为像dotglob
和nullglob
在bash
。