Linux

如何將空數組元素設置為零?

  • July 20, 2018

我正在編寫一個將命令結果發送到輸出數組的腳本。它涉及檢查伺服器的日誌並檢索它們的大小,但是在某些情況下伺服器具有故障轉移主機。在這些情況下,我需要腳本來檢查兩個主機並返回值。我遇到的問題是,如果任何輸出數組元素為空(意味著伺服器中不存在要檢查的文件,在其各自的回顯顯示中僅返回一個空格),它會導致數組索引發生變化。這意味著應該在輔助主機陣列集中的東西會撞到主陣列集中。相反,我希望將這些空索引儲存為 0 作為佔位符,以防止發生轉移。這是索引偏移明顯的地方:

echo The primary overall log value is ${output[0]}.
echo The primary obs log value is ${output[2]}.    
echo The primary tracks log value is ${output[4]}.  
echo
echo The secondary overall log value is ${output[6]}.
echo The secondary overall log value is ${output[8]}.
echo The secondary overall log value is ${output[10]}.

例如,如果輸出

$$ 2 $$和$$ 4 $$為空,輸出$$ 6 $$ 將向上移動到對應於輸出的行$$ 2 $$. 我已經嘗試過這個解決方案,但沒有運氣:

 s=0

 for x in "${output[@]}"
    do(
    x=
       if [[ -z $x ]];
       then(
       x=0
       echo $x)
       else echo
       fi
    s=s+1)
done

所有這一切都是在輸出回波發生之前吐出零,並且不會針對任何索引偏移進行調整。

注意:這是輸出數組的來源,以及下面的修復嘗試:

for h in "${host[@]}"
do
   for path in "${paths[@]}"
   do
           output+=( $(ssh $h du -sh $path) )
           for x in "${!output[@]}";
           do(
                   if [[ -z "${output[$x]}" ]];
                   then output[$x]=0;
                   fi;
           )
           done

   done
done

其中 host 和 path 已經定義了數組。我還要注意,對於只有一個主機可以訪問的情況,腳本功能很好,並且那裡的數組索引沒有問題。

例如,如果輸出

$$ 2 $$和$$ 4 $$為空,輸出$$ 6 $$將向上移動到對應於輸出的行$$ 2 $$.

在這種情況下,您實際上並沒有空值來代替 2 和 4,只是您的值比您預期的要少。

考慮數組分配:

array1=(a b c d)
array2=(A D)

第一個設置array1[0]to aarray1[1]tob等。第二個設置array2[0]toAarray2[1]to D。沒有辦法知道A和之間是否應該有空值D。他們需要明確地在任務中:

array2=(A "" "" D)

您可能正在以output其他方式填充數組,但由於您沒有顯示它是如何完成的,因此無法對其發表評論。您可能遇到與上述類似的情況:“空”值根本不會被填充output數組的任何值視為值。

如果您從擴展中分配給數組,並且依賴於分詞,那麼您將無法避免這種情況。(即使IFS只包含換行符,它也會將連續的空換行符折疊為一個,刪除空行)。如果您使用mapfile,則預設情況下空行應顯示為數組元素。


在任何情況下,將空數組元素歸零的循環都不起作用,因為您沒有分配給循環內的數組(根本沒有分配),即使您這樣做了,循環體也會在子shell中執行(由括號(...)),所以任何賦值都不會發生在循環體之外。

您不能真正使用 afor x in "${output[@]}"來有效地修改數組元素,因為x只獲取數組值的副本,修改它不會更改原始值。您需要遍歷數組索引才能指向數組:

somearray=(1 "" "" 4)
for i in "${!somearray[@]}"; do
   if [[ -z "${somearray[$i]}" ]]; then
       somearray[$i]=0;
   fi;
done
echo "${somearray[@]}"

列印1 0 0 4


在您添加的範常式式碼中,分配output+=( $(ssh $h du -sh $path) )不會添加任何空元素。缺少的路徑將從數組中省略。首先考慮一下,du $path 如果路徑不存在,則不列印任何內容。(除了一個錯誤,但這會進入 stderr,並且不會被命令替換擷取。)此外,即使它確實列印了一個空行(或空格/製表符),分詞也會刪除連續的空格。

試試 eg array=( $( printf "foo\n\nbar\n" ) ),它會創建一個包含兩個元素的數組。

此外,替換循環中的括號啟動了一個子shell,因此對數組的任何修改都只會在該子shell中生效。通常,您希望使用括號對 shell 命令進行分組,除非您知道您特別需要一個子 shell。

您可以在命令替換 ( ) 周圍加上引號,"$(ssh ... du)"以確保您得到一個字元串,但您可能希望將大小與路徑名分開。

嘗試像這樣將路徑及其大小收集到單個數組中:

for host in "${hosts[@]}"; do
   for path in "${paths[@]}"; do
       output="$(ssh "$host" du -sh "$path")"
       size="${output%%$'\t'*}"           # needs Bash/ksh/zsh
       size="${size:-0}"
       sizes+=( "$size" "$host:$path"  )
   done
done

現在,每個偶數數組元素都包含一個大小,每個奇數元素都包含一個相應的主機名和路徑,有點像拆分輸出的du結果。兩個參數擴展outputsize刪除選項卡後的所有內容,然後將大小替換為如果它是空的,則為零。

或者,您可以建構一個關聯數組,由主機+路徑索引:

declare -A array
...
   array["$host:$path"]=$size

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