带有基本名称的 find -exec 命令选项

Che*_*tar 3 find options basename

我有以下 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
Run Code Online (Sandbox Code Playgroud)

我用来$ img2pdf将每个图像转换为 PDF 文件。要做到这一点 :

$ find . -type f -name "*.jpg" -exec img2pdf "{}" --output $(basename {} .jpg).pdf \;
Run Code Online (Sandbox Code Playgroud)

结果 :

$ 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
Run Code Online (Sandbox Code Playgroud)

如何删除.jpgPDF 文件名的一部分?即,我想要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
Run Code Online (Sandbox Code Playgroud)

但似乎语法在我的命令中不起作用$ 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
Run Code Online (Sandbox Code Playgroud)

Kus*_*nda 5

您的命令的问题在于, shell甚至在开始运行之前find就执行了命令替换(作为评估参数应该是什么的步骤)。basenamefindfind

每当您需要运行除带有可选参数的简单实用程序之外的任何内容时find,例如,如果您需要执行任何管道、重定向或扩展(如您的问题中所示),您将需要使用 shell 来执行这些操作事物:

find . -type f -name '*.jpg' \
    -exec sh -c 'img2pdf --output "$(basename "$1" .jpg).pdf" "$1"' sh {} \;
Run Code Online (Sandbox Code Playgroud)

或者,更有效(每次调用sh -c都会处理一批找到的路径名),

find . -type f -name '*.jpg' -exec sh -c '
    for pathname do
        img2pdf --output "$(basename "$pathname" .jpg).pdf" "$pathname"
    done' sh {} +
Run Code Online (Sandbox Code Playgroud)

或者,与zsh,

for pathname in ./**/*.jpg(.DN); do
    img2pdf --output $pathname:t:r.png $pathname
done
Run Code Online (Sandbox Code Playgroud)

这使用 globbing 限定符.DN仅匹配常规文件 ( .),允许匹配隐藏名称 ( D),并在未找到匹配项时删除模式 ( N)。然后,它使用:t修饰符提取 的“尾部”(文件名组件)$pathname:r提取结果基本名称的“根”(无文件名后缀),然后添加.png到末尾。

请注意,上述所有变体都会将输出写入当前目录,无论在何处找到 JPEG 文件。如果所有 JPEG 文件都在当前目录中,则绝对不需要使用find,并且您可以对通配模式的扩展使用简单的循环*.jpg

for pathname in ./*.jpg; do
    img2pdf --output "${pathname%.jpg}.png" "$pathname"
done
Run Code Online (Sandbox Code Playgroud)

参数替换从 值的末尾${pathname%.jpg}删除。如果您想将输出写入找到JPEG 文件的原始目录,如果您使用多个目录,例如,类似的内容,您可能需要使用此替换.jpg$pathname basenamefind

find . -type f -name '*.jpg' -exec sh -c '
    for pathname do
        img2pdf --output "${pathname%.jpg}.pdf" "$pathname"
    done' sh {} +
Run Code Online (Sandbox Code Playgroud)

也可以看看: