是否可以使大括号扩展将 globing 的结果复制到不存在的文件中

是否可以使大括号扩展将 globing 的结果复制到不存在的文件中

在 Bash 中,大括号扩展不会将通配结果复制到不存在的文件。

例如,在当前目录中,有一个名为 的文件1.epub,我想将其转换为除扩展名外文件名相同的 pdf 文件。该 pdf 文件1.pdf尚不存在。

$ ebook-convert *.{epub,pdf}

结果文件是*.pdf.

在Bash中,我是否需要首先将epub文件的基本名称提取到变量中,然后使用该变量的值来命名pdf文件?

在 Bash 内部或其他 shell 中是否有更优雅的解决方案?

答案1

shell 技术使用循环。

在 sh 和其他类似 sh 的 shell 中,例如 bash 或 zsh:

for f in *.epub; do
  ebook-convert -- "$f" "${f%.epub}.pdf"
done

在 zsh 中,可以缩短为:

for f (*.epub(N)) ebook-convert -- $f $f:r.pdf

N如果没有匹配的文件,ullglob glob 限定符还可以避免错误。bash 没有等效项,但您可以nullglob预先全局设置该选项;在 ksh93 中,您还可以使用for f in ~(N)*.epub; do...

您可能rename安装了一个程序:man 1 rename

答案2

zmvin 中的实用程序可zsh与任何命令一起使用,并且适用于如下模式:

autoload zmv
zmv -Wn -p ebook-convert '*.epub' '*.pdf'

用于-n试运行 - 当您对结果感到满意时将其删除。

作为别名,它甚至可以更短,如下所示~/.zshrc

autoload zmv
alias ebc='noglob zmv -W -p ebook-convert '

现在命令行很简单:

ebc *.epub *.pdf

例子:

> ls *.epub
1.epub b2.epub
> ebc -n *.epub *.pdf
ebook-convert -- 1.epub 1.pdf
ebook-convert -- b2.epub b2.pdf

更多使用选项zmv文档

答案3

在 Bash 中,大括号扩展不会将通配结果复制到不存在的文件。

根据规范,确实不是。大括号扩展是 Bash 对每个命令执行的第一个扩展,而路径名扩展是最后一个。因此,当收到您的命令时

ebook-convert *.{epub,pdf}

, bash 首先执行大括号扩展以得到

ebook-convert *.epub *.pdf

,并且它仅在稍后执行路径名扩展 - 分别针对每个模式。除非设置了 nullglob shell 选项,否则与任何文件都不匹配的 glob 模式将扩展为自身,因此您无法使用此方法来生成尚不存在的 .pdf 文件的名称。

更重要的是,如果工作目录中有多个.epub文件,或者存在.pdf与您想要写入的文件不同的文件,那么该命令将扩展为具有潜在破坏性的文件。

在Bash中,我是否需要首先将epub文件的基本名称提取到变量中,然后使用该变量的值来命名pdf文件?

您可以避免实际将 EPUB 名称存储在变量中,但您确实需要首先找到 epub 名称,然后单独对其应用转换,特别是如果您要使用 glob 来标识 EPUB。

我建议使用 shell 函数:

epub_to_pdf() {
  for epub; do
    ebook-convert "${epub}" "${epub%.epub}.pdf"
  done
}

定义完成后,您只需为其指定 EPUB,而不是相应的 PDF:

epub_to_pdf *.epub

这也将适当地处理多个 EPUB。您可能不想每次都定义该函数,但您可以将定义放入您的函数中.bashrc以确保它始终可供您使用。

答案4

“优雅的解决方案”是 GNU Make 中的模式规则。如果我们有Makefile这样的:

%.pdf: %.epub
        ebook-convert -- $^ $@

那么你就可以

$ make 1.pdf

GNU Make 会发现它1.pdf不存在并且它与我们编写的模式规则的左侧匹配%.pdf。它将实例化该模式并看到右侧生成1.epub。然后它将运行该命令ebook-convert 1.epub 1.pdf

如果我们再次运行该命令,它将经历相同的模式匹配,然后查看1.pdf更新的命令1.epub并报告1.pdf最新的命令。

相关内容