动态重命名包含空格的文件

1 shell filenames rename

我想根据包含空格的数据动态重命名文件

Name="Abc DEF"
Name1="GHI JKL"

mv /sample/pdf/noriginalName.pdf /sample/outputPdf/${NAME}${Name1}".pdf"
Run Code Online (Sandbox Code Playgroud)

但它给了我一个错误,因为它在两者之间遇到了空间。

我怎样才能做到这一点?

Sté*_*las 5

别担心,你不是第一个,也不会是最后一个被它咬到的。这是有关 shell 的最常见问题,也是 shell 脚本中发现的大多数错误和安全漏洞的原因。这是由于早期 Unix 历史中 Bourne shell 和 Korn shell 的设计选择不当。

在 Bourne shell 及其大多数后代(ksh、ash、pdksh、mksh、bash、dash、yash...)中,不加引号的变量是 split+glob 运算符。

最好的证明:

$ var='*.txt,.*'
$ IFS=',' # default is space tab and newline
$ printf '<%s>\n' $var
<file.txt>
<.>
<..>
Run Code Online (Sandbox Code Playgroud)

外壳程序$var, 字符上进行了拆分,并在与相应模式匹配的文件列表中扩展了每个结果词(在本例中包含通配符)。

这就是为什么,在类似 Bourne 的 shell 中(除了zsh),您必须始终引用您的变量(除非您确实想要split和/或glob

$ printf '<%s>\n' "$var"
<*.txt:.*>
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下:

mv /sample/pdf/noriginalName.pdf "/sample/outputPdf/${NAME}${Name1}.pdf"
Run Code Online (Sandbox Code Playgroud)

或者:

mv /sample/pdf/noriginalName.pdf /sample/outputPdf/"${NAME}${Name1}".pdf
Run Code Online (Sandbox Code Playgroud)

(只要引用了变量,您将引号放在哪里并不重要)。

您只能通过以下方式禁用拆分:

IFS=
Run Code Online (Sandbox Code Playgroud)

您只能通过以下方式禁用通配符:

set -f # affects all globbing, not only the one done upon variable expansion.
Run Code Online (Sandbox Code Playgroud)

和:

IFS=; set -f
Run Code Online (Sandbox Code Playgroud)

您将获得与zsh参数扩展相同的行为,没有通配符,没有拆分。你仍然需要引用你的变量但是在

cmd "$var"
Run Code Online (Sandbox Code Playgroud)

如果您想在为空或未设置时cmd传递一个空参数$var(而不是根本没有参数)。一个典型的例子是[ -n "$var" ],如果您不引用$var,则测试将始终为真,因为 when$var为空,则解析为[ -n ]而不是[ -n '' ]

在 中zsh,globbing 和 splitting 不是在变量扩展时隐式完成的(除了 inshkshemulation 模式)。您必须使用特定的扩展运算符明确请求它:$=var用于分词、$~var用于通配符(或${~var};$~=var用于两者)。

没有这种问题的其他 shell 是fish,rc和 及其后代 ( es, akanga)。

(t)csh

cmd "$var"
Run Code Online (Sandbox Code Playgroud)

有帮助但还不够,因为如果$var包含换行符就不起作用。在那里,您需要:

cmd $var:q
Run Code Online (Sandbox Code Playgroud)