使用 find -exec 命令选项
1. 概述
在本教程中,我们将探讨 Linux find 命令的 -exec 参数。这个参数扩展了 find 的功能,并使其成为众所周知的瑞士军刀。
我们将讨论使用-exec来执行命令和shell函数,以及如何控制它们以提高它们的执行效率。
2. -exec 操作
find 命令由两个主要部分组成:表达式和操作。
当我们最初使用find时,我们通常从表达式部分开始。这部分允许我们指定一个过滤器来定义要选择的文件。
一个经典的例子是:
$ find Music/ -name *.mp3
Music/Gustav Mahler/01 - Das Trinklied vom Jammer der Erde.mp3
Music/Gustav Mahler/02 - Der Einsame im Herbst.mp3
Music/Gustav Mahler/03 - Von der Jugend.mp3
Music/Gustav Mahler/04 - Von der Schönheit.mp3
Music/Gustav Mahler/05 - Der Trunkene im Frühling.mp3
Music/Gustav Mahler/06 - Der Abschied.mp3
此命令将生成 Music 目录及其所有子目录中的 mp3 文件列表。
此示例中的操作部分是默认操作-print。此操作打印结果路径,中间带有换行符。如果没有指定其他操作,它将运行。
相比之下,-exec 操作允许我们在生成的路径上执行命令。
假设我们要在刚刚找到的 mp3 文件列表上运行 file 命令来确定其文件类型。我们可以通过运行以下命令来实现这一点:
$ find Music/ -name *.mp3 -exec file {} \;
Music/Gustav Mahler/01 - Das Trinklied vom Jammer der Erde.mp3:
Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
Music/Gustav Mahler/02 - Der Einsame im Herbst.mp3:
Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
Music/Gustav Mahler/03 - Von der Jugend.mp3:
Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
Music/Gustav Mahler/04 - Von der Schönheit.mp3:
Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
Music/Gustav Mahler/05 - Der Trunkene im Frühling.mp3:
Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
Music/Gustav Mahler/06 - Der Abschied.mp3:
Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
让我们剖析传递给 -exec 标志的参数,其中包括:
- 命令:file
- 占位符:{}
- 命令分隔符:\;
现在我们将深入探讨这三个部分。
3. 命令
任何可以被我们的 shell 执行的命令在这里都是可以接受的。
我们应该注意,这不是我们的 shell 执行命令,而是我们直接使用 Linux 的 exec 来执行命令。这意味着任何 shell 扩展在这里都不起作用,因为我们没有 shell。另一个影响是 shell 函数或别名不可用。
作为缺少 shell 函数的解决方法,我们可以导出它们并在文件中使用我们请求的函数调用 bash -c。
为了看到这一点,我们将继续使用 Mahler 的 mp3 文件目录。让我们创建一个 shell 函数来显示曲目名称和一些有关质量的详细信息:
function mp3info() {
TRACK_NAME=$(basename "$1")
FILE_DATA=$(file "$1" | awk -F, '{$1=$2=$3=$4=""; print $0 }')
echo "${TRACK_NAME%.mp3} : $FILE_DATA"
}
如果我们尝试对所有文件运行 mp3info 命令,-exec 会抱怨它不知道 mp3info:
find . -name "*.mp3" -exec mp3info {} \;
find: ‘mp3info’: No such file or directory
如前所述,要解决此问题,我们需要导出 shell 函数并将其作为生成的 shell 的一部分运行:
$ export -f mp3info
$ find . -name "*.mp3" -exec bash -c "mp3info \"{}\"" \;
01 - Das Trinklied vom Jammer der Erde : 128 kbps 44.1 kHz Stereo
02 - Der Einsame im Herbst : 128 kbps 44.1 kHz Stereo
03 - Von der Jugend : 128 kbps 44.1 kHz Stereo
04 - Von der Schönheit : 128 kbps 44.1 kHz Stereo
05 - Der Trunkene im Frühling : 128 kbps 44.1 kHz Stereo
06 - Der Abschied : 128 kbps 44.1 kHz Stereo
请注意,由于我们的某些文件名包含空格,因此我们需要引用结果占位符。
4. 结果占位符
结果占位符由两个大括号 {} 表示。
如果需要,我们可以多次使用占位符:
find . -name "*.mp3" -exec bash -c "basename \"{}\" && file \"{}\" | awk -F: '{\$1=\"\"; print \$0 }'" \;
01 - Das Trinklied vom Jammer der Erde.mp3
Audio file with ID3 version 2.4.0, contains MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
02 - Der Einsame im Herbst.mp3
Audio file with ID3 version 2.4.0, contains MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
03 - Von der Jugend.mp3
Audio file with ID3 version 2.4.0, contains MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
04 - Von der Schönheit.mp3
Audio file with ID3 version 2.4.0, contains MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
05 - Der Trunkene im Frühling.mp3
Audio file with ID3 version 2.4.0, contains MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
06 - Der Abschied.mp3
Audio file with ID3 version 2.4.0, contains MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
在上面的示例中,我们运行了 basename 以及 file 命令。为了让我们能够连接命令,我们生成了一个单独的 shell,如上所述。
5. 分隔符
我们需要为 find 命令提供分隔符,以便它知道我们的 -exec 参数在哪里停止。
可以为 -exec 参数提供两种类型的分隔符:分号 (;) 或加号 (+)。
由于我们不希望 shell 解释分号,因此需要对其进行转义 (\;)。
分隔符决定 find 处理表达式结果的方式。如果我们使用分号 (;),-exec 命令将分别对每个结果重复执行。另一方面,如果我们使用加号 (+),所有表达式的结果将被连接起来并作为一个整体传递给 -exec 命令,该命令只会运行一次。
让我们通过另一个例子来看看加号的用法:
$ find . -name "*.mp3" -exec echo {} +
./Gustav Mahler/01 - Das Trinklied vom Jammer der Erde.mp3 ./Gustav Mahler/02 -
Der Einsame im Herbst.mp3 ./Gustav Mahler/03 - Von der Jugend.mp3 ./Gustav Mahler/04 -
Von der Schönheit.mp3 ./Gustav Mahler/05 - Der Trunkene im Frühling.mp3
./Gustav Mahler/06 - Der Abschied.mp3
运行 echo 时,每个 echo 调用都会生成一个换行符,但由于我们使用了加号分隔符,因此只进行了一次 echo 调用。让我们将此结果与分号版本进行比较:
$ find . -name "*.mp3" -exec echo {} \;
./Gustav Mahler/01 - Das Trinklied vom Jammer der Erde.mp3
./Gustav Mahler/02 - Der Einsame im Herbst.mp3
./Gustav Mahler/03 - Von der Jugend.mp3
./Gustav Mahler/04 - Von der Schönheit.mp3
./Gustav Mahler/05 - Der Trunkene im Frühling.mp3
./Gustav Mahler/06 - Der Abschied.mp3
从性能角度来看,我们通常更喜欢使用加号分隔符,因为为每个文件运行单独的进程可能会导致 RAM 和处理时间的严重损失。
但是,在以下情况之一,我们可能更喜欢使用分号分隔符:
- -exec 运行的工具不接受多个文件作为参数。
- 一次在如此多的文件上运行该工具可能会占用太多内存。
- 我们希望尽快开始获得一些结果,尽管需要更多时间才能获得所有结果。
六,结论
在本文中,我们学习了在 Linux 中运行 find 命令时如何使用 -exec 参数。我们解释了这个参数的各个部分,以及如何使用它们来有效地运行我们的命令。