用全局模式定义的变量替换Bash


10

以下示例说明了该问题。为什么FILENAME在使用替换时回显并被视为图案时打印正确?

#!/bin/bash

FILEPATH_WITH_GLOB="/home/user/file_*"
FILENAME=$(basename "$FILEPATH_WITH_GLOB")
echo $FILENAME                #file_1234
echo ${FILENAME:1:5}          #ile_*   <---why is this not ile_1

Answers:


15
FILEPATH_WITH_GLOB="/home/user/file_*"

现在,FILEPATH_WITH_GLOB包含/home/user/file_*

FILENAME=$(basename "$FILEPATH_WITH_GLOB")

FILENAME包含file_*

echo $FILENAME                #file_1234

$FILENAME在列表上下文中不加引号时,该扩展将进行split + glob运算符,因此将其扩展到匹配文件的列表:在参数扩展时执行文件名生成

echo ${FILENAME:1:5}          #ile_*   <---why is this not ile_1

在列表上下文中它仍然是未引用的参数扩展,因此仍然经历split + glob。但是,此ile_*模式与任何文件都不匹配,因此它会扩展为自身。

您可能想要的是:

shopt -s nullglob # have globs expand to nothing when they don't match
set -- /home/user/file_* # expand that pattern into the list of matching 
                         # files in $1, $2...
for file do  # loop over them
  filename=$(basename -- "$file")
  printf '%s\n' "$filename" "${filename:1:5}"
done

或者您可以将它们存储在数组中:

shopt -s nullglob
files=(/home/user/file_*)

如果您只关心第一个匹配项,或者知道只有一个匹配项,则可以将该文件称为$filesbash具有通常烦人的行为,而不是$files扩展到${files[0]}数组的所有元素(此行为继承自ksh,固定为zsh),但是在这里,这只是一次想要的行为。


感谢您的解释。FILEPATH_WITH_GLOB=`echo /home/user/file_*` 解释完后设法解决。
TheMeaningfulEngineer 2015年

@Alan,这是错误的解决方法。您要在此处使用数组。任一位置参数如在我的例子($ 1,$ 2 ...)或一个bash状阵列:files=(/home/user/file_*)
斯特凡Chazelas

(并且所有大写变量实际上应该保留给环境变量使用,echo不应用于任意数据,并且在列表上下文中不应该将变量不加引号)。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.