![find -exec 命令选项与基本名称](https://linux22.com/image/201323/find%20-exec%20%E5%91%BD%E4%BB%A4%E9%80%89%E9%A1%B9%E4%B8%8E%E5%9F%BA%E6%9C%AC%E5%90%8D%E7%A7%B0.png)
我有以下 JPEG 文件:
$ ls -l
-rw-r--r-- 1 user group 384065 janv. 21 12:10 CamScanner 01-10-2022 14.54.jpg
-rw-r--r-- 1 user group 200892 janv. 10 14:55 CamScanner 01-10-2022 14.55.jpg
-rw-r--r-- 1 user group 283821 janv. 21 12:10 CamScanner 01-10-2022 14.56.jpg
我用来$ img2pdf
将每个图像转换为 PDF 文件。要做到这一点 :
$ find . -type f -name "*.jpg" -exec img2pdf "{}" --output $(basename {} .jpg).pdf \;
结果 :
$ ls -l *.pdf
-rw-r--r-- 1 user group 385060 janv. 21 13:06 CamScanner 01-10-2022 14.54.jpg.pdf
-rw-r--r-- 1 user group 201887 janv. 21 13:06 CamScanner 01-10-2022 14.55.jpg.pdf
-rw-r--r-- 1 user group 284816 janv. 21 13:06 CamScanner 01-10-2022 14.56.jpg.pdf
如何删除.jpg
PDF 文件名的一部分?即,我想要CamScanner 01-10-2022 14.54.pdf
又不想要CamScanner 01-10-2022 14.54.jpg.pdf
。
单独使用,$ basename filename .extension
打印不带扩展名的文件名,例如:
$ basename CamScanner\ 01-10-2022\ 14.54.jpg .jpg
CamScanner 01-10-2022 14.54
$ find
但似乎语法在我的命令中不起作用。知道为什么吗?
注意:如果您替换$ img2pdf
为$ echo
相同的,$ basename
则不会删除该.jpg
部分:
$ find . -type f -name "*.jpg" -exec echo $(basename {} .jpg).pdf \;
./CamScanner 01-10-2022 14.56.jpg.pdf
./CamScanner 01-10-2022 14.55.jpg.pdf
./CamScanner 01-10-2022 14.54.jpg.pdf
答案1
您的命令的问题find
在于周围的命令替换basename
是由 shell 执行的前它甚至开始运行find
(作为评估参数应该find
是什么的一个步骤)。
每当您需要运行除带有可选参数的简单实用程序之外的任何内容时find
,例如,如果您需要执行任何管道、重定向或扩展(如您的问题中所示),您将需要使用 shell 来执行这些操作事物:
find . -type f -name '*.jpg' \
-exec sh -c 'img2pdf --output "$(basename "$1" .jpg).pdf" "$1"' sh {} \;
或者,更有效(每次调用sh -c
都会处理一批找到的路径名),
find . -type f -name '*.jpg' -exec sh -c '
for pathname do
img2pdf --output "$(basename "$pathname" .jpg).pdf" "$pathname"
done' sh {} +
或者,与zsh
,
for pathname in ./**/*.jpg(.DN); do
img2pdf --output $pathname:t:r.png $pathname
done
这使用 globbing 限定符.DN
仅匹配常规文件 ( .
),允许匹配隐藏名称 ( D
),并在未找到匹配项时删除模式 ( N
)。然后,它使用:t
修饰符提取 的“尾部”(文件名组件)$pathname
,:r
提取结果基本名称的“根”(无文件名后缀),然后添加.png
到末尾。
请注意,上述所有变化都会将输出写入当前目录,无论在何处找到 JPEG 文件。如果所有 JPEG 文件都在当前目录中,则绝对不需要使用find
,并且您可以对通配模式的扩展使用简单的循环*.jpg
:
for pathname in ./*.jpg; do
img2pdf --output "${pathname%.jpg}.png" "$pathname"
done
参数替换从 值的末尾${pathname%.jpg}
删除。您可能想使用此替换.jpg
$pathname
代替 basename
如果您想将输出写入找到 JPEG 文件的原始目录,在您使用find
多个目录的情况下,例如,类似
find . -type f -name '*.jpg' -exec sh -c '
for pathname do
img2pdf --output "${pathname%.jpg}.pdf" "$pathname"
done' sh {} +
也可以看看:
答案2
从务实的角度来看,一旦您达到问题末尾所描述的状态:
./CamScanner 01-10-2022 14.56.jpg.pdf
./CamScanner 01-10-2022 14.55.jpg.pdf
./CamScanner 01-10-2022 14.54.jpg.pdf
您可以选择使用rename
来获取所需的最终文件名:
~ rename 's/jpg.pdf/pdf/'
答案3
@Ulrich Schwarz 的评论很恰当。为了使其完整,我们假设您没有任何带引号或单引号的文件名。
调整您的find
语法以简单地输出不含 .jpg 的基本名称,然后在适当的情况下使用和扩展名awk
来重建img2pdf
语法:.jpg
.pdf
此find
命令将输出裸基名称:
$ find . -type f -name "*.jpg" -exec basename {} .jpg \;
CamScanner 01-10-2022 14.56
CamScanner 01-10-2022 14.55
CamScanner 01-10-2022 14.54
现在将这些基本名称传递给awk
并让 awk 构造正确的语法img2pdf
:
$ find . -type f -name "*.jpg" -exec basename {} .jpg \; | \
awk '{print "cp -vp '\''" $0 ".jpg'\'' --output '\''" $0 ".pdf'\''"}'
img2pdf 'CamScanner 01-10-2022 14.56.jpg' --output 'CamScanner 01-10-2022 14.56.pdf'
img2pdf 'CamScanner 01-10-2022 14.55.jpg' --output 'CamScanner 01-10-2022 14.55.pdf'
img2pdf 'CamScanner 01-10-2022 14.54.jpg' --output 'CamScanner 01-10-2022 14.54.pdf'
如果该语法看起来没问题,则将其通过管道传输到您最喜欢的 shell。