如何防止双重转义?

如何防止双重转义?

我正在尝试将一堆图像合并成一个 pdf 文件。我跑了gm convert *.jpg out.pdf,它成功了,但图像的顺序不正确。
我发现ls -v它们的顺序正确,所以我尝试了gm convert `ls -v *.jpg` out.pdf,但失败了,因为文件名称中包含空格。

所以我检查了 ls 选项并尝试了gm convert `ls -Qv *.jpg` out.pdfgm convert `ls -bv *.jpg` out.pdf但都失败了,因为据我所知,文件名被转义了两次(在第一种情况下使用 \" ,在第二种情况下在空格前使用 \\ )。
为什么这是这样发生了,如何正确转义文件名,即仅使用一次 zsh(如果相关的话)。

答案1

你不能用这种方式转义。您可以使用引号或反斜杠来理解它们,例如 shell 解析。

没有什么可以逃避变量扩展或命令替换时进行的分词(这与命令行的 shell 解析(标记化)不同)。

您可以做的就是更改内部字段分隔$IFS符以仅在换行符上拆分(但请注意,除了 with 之外zsh,您还需要禁用文件名生成(尽管不是为了显然扩展*.jpg),这是在不带引号的命令替换时完成的另一件事,除非您可以保证没有文件名包含通配字符):

set -f # disable filename generation
IFS='
' # set IFS  to newline character
IFS=$'\n' # alternative for ksh/zsh/bash
gm convert $(set +f; ls -v ./*.jpg) out.pdf # you also need ./ in case file
                                            # names start with -

(假设所有文件名都不包含换行符)

set -fin zsh(除非在 sh/ksh 模拟中)禁用读取rc文件(想想zsh -f, csh -f),一旦 shell 已经启动,它就没有任何作用,因此是无害的。

使用zsh,您可以将其缩短为:

gm convert ${(f)"$(ls -v ./*.jpg)"} out.pdf

(f)缩写(ps:\n:)是按换行符分割。

或者,您可以使用ls引用来构建一个 shell 命令行(如果您愿意,可以使用 shell 语法中的 shell 代码)来传递给eval它,让 shell 对其进行评估并运行它:

ksh93,zshbash:

eval "images=($(ls --quoting-style=shell -v ./*.jpg))"
gm convert "${images[@]}" out.pdf

但是使用zsh,您可以简单地执行以下操作:

gm convert ./*.jpg(n) out.pdf

(n)是一个通配限定符,告诉 shell 按数字方式对生成的文件名进行排序。

相关内容