Bash
使用從全域模式定義的變數進行 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
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
),但在這裡,這將是一次想要的行為。