使用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*标志的参数,其中包括:
- 一个命令:文件
- 占位符:{}
- 命令分隔符:;
我们将深入介绍这三个部分。
3. 命令
任何可以由我们的 shell 执行的命令在这里都是可以接受的。
*我们应该注意,这不是我们的 shell 执行命令,而是我们直接使用 Linux 的exec *来执行命令。**这意味着任何 shell 扩展在这里都不起作用,因为我们没有 shell。另一个影响是 shell 函数或别名不可用。
作为我们缺少的 shell 函数的解决方法,我们可以导出它们并在我们的文件中使用我们请求的函数调用*bash -c *。 一个例子是有序的。我们将继续我们的马勒 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运行的工具 不接受多个文件作为参数
- 一次在这么多文件上运行该工具可能会占用太多内存
- 我们希望尽快开始获得一些结果,即使获得所有结果需要更多时间