Bash

使用從全域模式定義的變數進行 Bash 替換

  • June 17, 2015

下面的例子解釋了這個問題。為什麼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),但在這裡,這將是一次想要的行為。

引用自:https://unix.stackexchange.com/questions/210280