Bash 脚本通配符不适用于现有文件

Bash script wildcard not working with existing file

我有一个脚本将带有通配符的 hdfs 文件路径分配给变量,但通配符不知何故不起作用。所以我写了这个测试脚本,在我的主目录

中创建了一个文件some-file.txt
FILEPATH=~/some*
echo $(ls $FILEPATH)
echo $FILEPATH

APPJAR=hdfs:///user/myusername/myproject/lib/myproject*.jar
echo $(hdfs dfs -ls $APPJAR)
echo $APPJAR

输出让我感到惊讶,因为前 3 行产生了我预期的结果,但 hdfs 行没有。

/home/myusername/some-file.txt
/home/myusername/some-file.txt
-rw-r--r-- 3 myusername supergroup 188267249 2018-04-19 23:20 hdfs:///user/myusername/myproject/lib/myproject-1.0.1-SNAPSHOT-f7b.jar
hdfs:///user/myusername/myproject/lib/myproject*.jar

显然,由于 hdfs dfs -ls 命令起作用,因此该文件存在于 HDFS 中。但是为什么 APPJAR 变量没有变成实际的文件名呢? hdfs命令有问题吗?

简单的答案是 Bash 不会自动感知像 HDFS 这样的任意协议。例如,您不会期望 https://example.org/*.txt 会扩展。如果您安装 HDFS 文件系统驱动程序并挂载该目录,它将正常完成。

这里的关键是 shell 不识别 hdfs:// URL;在那种情况下,我很确定扩展是由 hdfs 命令完成的(或者 not 完成,如果没有 hdfs 命令)。当 shell 看到 hdfs:///user/myusername/myproject/lib/myproject*.jar 时,它会查找名为 "hdfs:" 的目录(在当前工作目录下)(是的,“:”在文件名中是合法的),并且一个 "user" 子目录,等等。没有找到它们,它使通配符未展开。

我有几个一般性的建议:

  • 不用echo $(somecommand),直接用运行命令即可。使用 $( ) 捕获命令的输出,然后使用 echo 将其转回输出只会增加一层混乱。

  • 使用set -x 使shell 在执行之前打印命令,这将让您看到扩展发生在哪里。例如,当您分配 FILEPATH=~/some* 时,您会看到 ~ 在 分配完成之前扩展到主目录的路径 ,但是 * 直到后来才展开。

  • 如果您不希望变量引用被拆分成单词并扩展嵌入的通配符,请在变量引用周围加上双引号。 echo "$variable" 将打印 $variable 的内容,而 echo $variable 将在打印前扩展通配符。

  • 不要使用全部大写的变量名;改用小写或混合大小写。有大量具有特殊含义的全大写变量,如果您尝试将其中一个用于其他用途(例如 PATH),您将遇到问题。