如何提取資料夾、拆分鍵和值中的檔案名稱並將其保存在關聯數組中?

如何提取資料夾、拆分鍵和值中的檔案名稱並將其保存在關聯數組中?

我有以下腳本,應該可以解決標題中的問題,但顯然它無法將值分配給鍵。原因是意外錯誤還是腳本有重大錯誤?

資料夾名稱是 gem 檔案的名稱,例如gem-file-foo-1.2.3

在此範例中,鍵應該是版本號,如果同一個 gem 有多個版本,gem-file-foo則值應該是版本號或多個版本號的字串。1.2.3

它不會輸出任何鍵echo "${!my_gems[@]}"...為什麼不?

#!/bin/bash

directory=$GEM_HOME/gems
declare -A my_gems

get_gemset_versions () {

last_key=""
values=""

FIND_RESULTS=$(find $directory -maxdepth 1 -type d -regextype posix-extended -regex "^${directory}\/[a-zA-Z0-9]+([-_]?[a-zA-Z0-9]+)*-[0-9]{1,3}(.[0-9]{1,3}){,3}\$")

 printf "%s\n" $FIND_RESULTS | sort | 
  while read -r line; do
    line=${line##*/}
            
    KEY="${line%-*}"
            
    VALUE="${line##*-}"
  
        if [[ $last_key -eq "" ]]; then
            last_key=$KEY
        fi
        
        if [[ $last_key -eq $KEY ]]; then
            values="$values ${VALUE}"
        else
            values="${VALUE}"
            last_key=$KEY
        fi
        
        my_gems[$KEY]=$values
    done
 
    echo "${!my_gems[@]}"

 }


get_gemset_versions

$last_key此外,總結$key相同寶石包的邏輯似乎是錯誤的。這不一定是問題的一部分,但如果您能指出我在這裡是否應用了一些錯誤的邏輯,那就太好了。

謝謝

答案1

你有:

printf "%s\n" $FIND_RESULTS | sort | 
  while read -r line; do
    ...
    done
 
    echo "${!my_gems[@]}"

其中,無論縮排如何,都echo位於管道之外。預設情況下,Bash 在子 shell 中運行管道的所有部分,因此循環內的分配while在管道結束後不可見。 Shellcheck.net 也對此發出警告:

Line 32:
        my_gems[$KEY]=$values
        ^-- SC2030: Modification of my_gems is local (to subshell caused by pipeline).

遺憾的是它沒有提供解決方法。

在 Bash 中,您可以啟用該lastpipe選項,或使用進程替換來取代管道:

shopt -s lastpipe
echo test | while read line; do
    out=$line
  done
echo "out=$out"

或者

while read line; do
  out=$line
done < <(echo test)
echo "out=$out"

lastpipe如果您在互動式 shell 中嘗試它可能不起作用,因為它與作業控制相關不是正在啟用。

看:為什麼我的變數在一個「while read」迴圈中是本地變量,但在另一個看似相似的循環中卻不是?


無論如何,這看起來有點奇怪:

FIND_RESULTS=$(find ...)

 printf "%s\n" $FIND_RESULTS 

find輸出由換行符號分隔的檔案名,只要您知道檔案名稱不包含任何檔案名稱就可以。但在這裡,變數的往返以及未加引號的擴展中的單字分割也會用空格分割任何檔案名稱。

直接跑就可以了find ... | while ...。或者while ...; done < <(find...)

另請注意,您幾乎總是希望使用while IFS= read -r line; do, 來防止read破壞前導和尾隨空格。好吧,我希望你的檔案名稱也不包含這些內容,但無論如何。

我現在找不到好的參考問題,但這是特定於IFS包含空格的。其他前導和尾隨分隔符號不會read只使用一個欄位來刪除。例如,IFS=": " read -r foo <<< "::foobar "離開的foo字面意思是::foobar。冒號保留,但尾隨空格消失。

相關內容