在双引号变量扩展后使用 shell glob(通配符 (*))

在双引号变量扩展后使用 shell glob(通配符 (*))

我读到,最佳实践是在 Bash 中双引号所有变量扩展。我还读到,*在双引号变量扩展之后不能立即使用 shell glob(通配符( ))。当人们想要使用从变量扩展出来的正则表达式模式的值时,这些情况会发生冲突。

我有时想要将正则表达式与通配符结合起来的原因是为了让我的正则表达式保持最小、更整洁,符合我个人的口味。

我的特殊问题

我将 phpmyadmin 下载到我的文档根目录中并将其解压缩,但我无法mv通过放入变量中的正则表达式模式重命名它,并且在扩展其变量时可用。这是确切的跟踪:

userName@compName:/var/www/html# ll
total 11336
drwxr-xr-x  3 root root     4096 Feb 14 07:04 ./
drwxr-xr-x  3 root root     4096 Feb 14 06:56 ../
-rw-r--r--  1 root root      612 Feb 14 06:57 index.nginx-debian.html
drwxr-xr-x 12 root root     4096 Dec 23 08:50 phpMyAdmin-4.7.7-all-languages/
-rw-r--r--  1 root root 11589684 Dec 23 14:08 phpMyAdmin-latest-all-languages.zip
userName@compName:/var/www/html# echo $pma
[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]
userName@compName:/var/www/html# mv "$pma"*/ phpmyadmin/
mv: cannot stat '[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]*/': No such file or directory

如果我将变量扩展取消引用,${pma}我确实能够将变量扩展和正则表达式结合起来,如 中所示${pma}*,但对我来说,如果可以的话,毫无例外地遵循最佳实践很重要。

我的问题

如何保留变量扩展双引号,但仍使用带有通配符的提取值?

答案1

如果使用双引号,保存在变量中的文件名通配模式将不会通配文件名。是双引号阻止文件名被通配,而不是*末尾的通配符或引号和 的组合*

我们经常告诉网站上的用户“引用他们的变量”,我们这样做是因为未引用的变量的值会经历分词和文件名通配,而这通常不是我们想要的。例如,密码可能是[hello] world*和 ,在命令行上包含-p $password该密码将根据当前目录中存在的文件执行“有趣”的操作(并且由于空间的原因,它可能根本不起作用)。另请参阅问题“忘记在 bash/POSIX shell 中引用变量的安全隐患

您在这里想要做的与我们通常想要做的相反避免,即使用变量中的文件名通配模式调用文件名通配。

如果您确实不能依赖提取的目录的名称来保持稳定,更好的(如“更干净的”)解决方案可能是确保它是仅有的临时目录中的东西,然后只需*将其移动到位(可能在此过程中更改其名称,以便您确定它的名称)。

这比简单地删除变量周围的引号更好,因为文件名通配模式可能匹配除您期望的单个名称之外的其他名称,具体取决于目录中可用的其他内容。

这是我的答案的一个变体你之前的问题:

#!/bin/sh -ex

destdir="/var/www/html/phpmyadmin"

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT    # remove temporary directory on termination

wget -O "$tmpdir/archive.zip" \
    "https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.zip"

cd "$tmpdir" && {
    unzip archive.zip
    rm -f archive.zip

    # The only thing in the current (temporary) directory now is the
    # directory with the unpacked zip file.

    mkdir -p "$destdir"
    mv ./* "$destdir"/phpmyAdmin
} 

上述内容可以归纳为五个步骤:

  1. 创建一个空目录(并将当前工作目录更改为该目录)。
  2. 获取存档。
  3. 提取存档。
  4. 删除存档。
  5. 现在更改空目录中单独文件夹的名称。

答案2

如何保留变量扩展双引号,但仍使用带有通配符的提取值?

你不能1 ,而你不想;如果没有它们,您的命令也可以完美运行(我相当确定这一点在该问题的早期删除变体之一中也已指出)。

$ mkdir phpMyAdmin-4.7.7-all-languages
$ pma=[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]
$ echo $pma
[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]
$ echo $pma*/
phpMyAdmin-4.7.7-all-languages/
$ mv $pma*/ phpmyadmin
$ ls
phpmyadmin

引用变量的目的是确保shell 通配符场分裂不要发生。这次你实际上希望这种情况发生,所以引用会适得其反。

值得理解为什么这些准则存在;它们不是一揽子规则,如果它们不适合您,那么您可能会遇到它们不适用的情况。在不理解它们的情况下努力“毫无例外地遵循最佳实践”是完全错误的。


除此之外,这个:

我还了解到,在双引号变量扩展之后不能立即使用 shell glob(通配符(*))。

不是真的。

$ tmp=php
$ echo "$tmp"*
phpmyadmin

1可以use eval,但这完全没有意义,我不会进一步跟进。

相关内容