使用 glob 模式定义的变量进行 Bash 替换

使用 glob 模式定义的变量进行 Bash 替换

下面的例子解释了这个问题。为什么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),但在这里,这将是一次想要的行为。

相关内容