![查找所有不存在具有不同扩展名的其他文件的文件](https://linux22.com/image/1405813/%E6%9F%A5%E6%89%BE%E6%89%80%E6%9C%89%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%85%B7%E6%9C%89%E4%B8%8D%E5%90%8C%E6%89%A9%E5%B1%95%E5%90%8D%E7%9A%84%E5%85%B6%E4%BB%96%E6%96%87%E4%BB%B6%E7%9A%84%E6%96%87%E4%BB%B6.png)
我想使用 find 命令来查找所有具有特定扩展名(avi)的文件,其中具有另一个扩展名(mp4)的相同文件名尚不存在。
因此考虑这些文件:
a.avi
a.mp4
c.avi
它只会导致找到文件 c.avi。
答案1
这样可以吗?
find . -name '*.avi' -type f -execdir bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' {} \; -print
我将尽力解释它是如何工作的。
其实很简单:在当前目录中查找所有名称带有avi
扩展名的文件。对于每个文件,假设它是X.avi
目录中的文件,则执行以下execdir
命令:
bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' {}
{}
在我们的测试用例中,其中被文件名替换X.avi
。因此,这就像
bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' X.avi
此时,我要强调的是,对于文件名中的空格和其他奇怪的符号,这是 100% 安全的!现在你看到 bash 将执行的代码片段了吗?我的意思是这个代码片段
f=("${0%avi}"*);((${#f[@]}==1))
它将通过将第 0 个位置参数设置为我们的文件名来执行;在我们的测试示例中它是X.avi
。
该部分"${0%avi}"
将扩展为文件名,并avi
删除尾随部分(顺便说一句,此时此文件名保证具有此扩展名),并且该部分"${0%avi}"*
将扩展为当前目录(记住,包含该文件的目录)中具有扩展名的所有文件.avi
。在我们的测试示例中,这就像:
X.*
然后我们用这些元素构建一个数组f
,最后,bash
如果f
只包含一个元素(因此,在我们的测试示例中很可能f
只包含一个元素X.avi
),则退出此过程,否则失败。如果成功,我们将打印文件名。
答案2
具有 2 个 exec() 的解决方案:
查找 . -name '*.avi' -print | \ perl -n -e '$x = $_; $x =~ s/\.avi\s*$/.mp4/; (-e $x) || 打印'
脚步:
- 这些是你正在寻找的机器人
- 对于每个输入行/文件,测试相应的 .mp4 文件,如果未找到,则回显 .avi 文件名
- 将输入行复制到 $x
- 在 $x 中用 .mp4 替换 .avi (但仅限于行尾)
- 如果相应的 .mp4 文件存在,我们就完成这一行,否则打印输入行
答案3
另一种选择:查找所有.mp4
和.avi
文件,然后从列表中删除同时存在两个扩展名的所有文件,然后删除剩余的 .mp4 文件:
find . -name '*.avi' -or -name '*.mp4' |
rev | sort -t. -k2 -k1,1 | uniq -s3 -u | grep -v '^4pm' | rev | sort
(假设没有文件名称中包含换行符。)
答案4
具有 3 个 exec() 的解决方案:
find . -name '*.avi' -print | \
sed 's/\(.*\)\.avi$/if [ ! -f "\1.mp4" ]; then echo "\1.avi"; fi/' | \
sh
脚步:
- 这些是你正在寻找的机器人
- 删除 .avi 文件扩展名;编写一串 sh 命令,测试相应的 .mp4 文件,如果未找到,则回显 .avi 文件名
- 评估 sh 命令