如何强制bash扩展变量以将其作为参数传递?

Yaj*_*ajo 5 variables bash expand

我发现了一个奇怪的行为,我不知道如何解决.

$ var1=*

$ echo $var1
Audiobooks Downloads Desktop (etc.)

$ ls $var1
Audiobooks:

Downloads:
(etc)
Run Code Online (Sandbox Code Playgroud)

一切似乎都好.在声明时,变量被扩展,其他一切都可以工作.但看到这个:

$ var2=~/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm

$ echo $var2
/home/yajo/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm

$ ls $var2
ls: no se puede acceder a /home/yajo/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm: No existe el fichero o el directorio

$ ls /home/yajo/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm
/home/yajo/rpmbuild/RPMS/noarch/enki-12.10.3-1.fc18.noarch.rpm  /home/yajo/rpmbuild/SRPMS/enki-12.10.3-1.fc18.src.rpm
/home/yajo/rpmbuild/RPMS/noarch/enki-12.10.3-1.fc19.noarch.rpm  /home/yajo/rpmbuild/SRPMS/enki-12.10.3-1.fc19.src.rpm
Run Code Online (Sandbox Code Playgroud)

这一次,声明只会~被扩展,这就产生了我无法将其作为参数传递给它ls.但是,传递相同的字符串会产生预期的结果.

问题是:

  • 为什么有时会扩大,有时不会?
  • 如何模仿的行为$var1$var2

谢谢.

额外说明:

我尝试使用双引号和单引号,但结果相同.

Gor*_*son 10

shell解析命令行的各个方面的顺序并不明显,这对于这样的事情很重要.

首先,通配符不会扩展通配符,它​​们在替换变量值后会被扩展(注意:在这些示例中,我假装我有你的文件系统):

$ var1=*
$ echo "$var1"   # double-quotes prevent additional parsing of the variable's value
*
$ echo $var1     # without double-quotes, variable value undergoes wildcard expansion and word splitting
Audiobooks:

Downloads:
(etc)
Run Code Online (Sandbox Code Playgroud)

顺便说一句,~ 在声明中得到了扩展,使事情更加混乱:

$ var2=~
$ echo "$var2"   # again, double-quotes let me see what's actually in the variable
/home/yajo
Run Code Online (Sandbox Code Playgroud)

问题~/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm1是虽然shell *在替换后对值进行了通配符扩展(),但是它没有做扩展扩展({SRPMS,RPMS/*}),所以它实际上是在查找名称中带有大括号和逗号的目录名...而没有找到任何.

处理此问题的最佳方法通常是将文件列表存储为数组; 如果你这样做,一切都会在声明时得到扩展:

$ var2=(~/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm)
$ echo "${var2[@]}"   # This is the proper way to expand an array into a word list
/home/yajo/rpmbuild/RPMS/noarch/enki-12.10.3-1.fc18.noarch.rpm  etc...
Run Code Online (Sandbox Code Playgroud)

请注意,数组是bash扩展,并且在普通POSIX shell中不起作用.所以一定要开始编写脚本#!/bin/bash,而不是#!/bin/sh.