下面的例子解释了这个问题。为什么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
答案1
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_*)
如果您只关心第一个匹配项,或者您知道只有一个匹配项,则可以将该文件引用为$files
.bash
具有通常令人讨厌的行为,它$files
扩展到${files[0]}
而不是数组的所有元素(从 继承的行为ksh
,在 中固定zsh
),但在这里,这将是一次想要的行为。