![如何找到 bash 陣列索引號的字串長度?](https://rvso.com/image/231058/%E5%A6%82%E4%BD%95%E6%89%BE%E5%88%B0%20bash%20%E9%99%A3%E5%88%97%E7%B4%A2%E5%BC%95%E8%99%9F%E7%9A%84%E5%AD%97%E4%B8%B2%E9%95%B7%E5%BA%A6%EF%BC%9F.png)
在 bash 中,假設某個函數會產生一個未知長度的簡單陣列。該數組將被轉換並印在螢幕上:每行旁邊都有一個小索引號,可以從中進行選擇。空間有限,演示必須完美無缺,工具集是……嗯,沒有多餘的裝飾,我想說。
我怎樣才能找到字串長度的索引號碼本身(出於格式化目的)這不是數組上的值。例如,如果數組有 334,345 個項目(您將使用 列印最後一個項目echo ${hugearray[334344]}
),那麼這6
就是我要查找的內容。
ncurses
我必須留在 bash 中,因為目標系統中沒有 tput 或其他「花哨」的格式化實用程式。只打擊本身。
${#WORD[@]}
給了我項目的總數,從中我建立了一些基本的構造來獲得它:
$〉pkglist+=($(brew list -1)) # ← I'm testing on a Mac.
$〉printf "%s\n" ${pkglist[@]}
automake
…
xquartz
$〉echo ${#pkglist[@]}
68
$〉indexlength=${#pkglist[@]}
$〉echo ${#indexlength}
2
它可以工作,但並不完全優雅。為我辯護,我不是開發者但我有點希望已經有更好、更簡單的方法來做到這一點,嵌套間接或其他一些 bash 巫毒。但是常規的東西對實際數據的作用已經足夠令人困惑了,我認為最好在後悔之前先問一下(目標系統只有根帳戶)。有沒有?
謝謝!
答案1
如果您使用的是 Macos,則應該可以存取 zsh,因此不必使用 bash。
在 zsh 中,陣列長度就像$#array
在 csh 中一樣,您可以嵌套參數擴充運算符,因此您可以執行${#${#array}}
1 來取得陣列長度的十進位表示形式的長度。
$ a=(qwe asdasd qewqw)
$ () {printf "%${#${#a}}d %s\n" "${@:^a}"} {1..$#a}
1 qwe
2 asdasd
3 qweqe
$ a=( {a..m} )
$ () {printf "%${#${#a}}d %s\n" "${@:^a}}" {1..$#a}
1 a
2 b
3 c
4 d
5 e
6 f
7 g
8 h
9 i
10 j
11 k
12 l
13 m
請注意,所有array=(...)
, array+=(...)
,{x..y}
均已由 bash 從 zsh 複製(通常透過 ksh 間接複製)。{1..$expansion}
在 zsh 或 ksh 中有效,但在 bash 中無效。
數組${a:^b}
壓縮運算子和() {code} args
匿名函數仍然是 zsh 特有的。
如果您必須使用 bash,那麼像您這樣分兩步驟進行可能就最好了。
您可以在一次擴充中完成此操作$(((l=${#array[@]}),SHLVL[l=\${#l}],l))
,依賴陣列索引的延遲評估,但這對易讀性沒有幫助,並且可能無法面向未來。
另請注意,在 bash 中(就像在 ksh 中,不幸的是,bash 的數組設計被複製了),數組並不是真正的數組,而是更像關聯數組,鍵為正整數並從 0 開始(與大多數其他 shell 不同,1)
bash-5.1$ a=( [5]=123 [123]=qwe [4567]=asd )
bash-5.1$ typeset -p a
declare -a a=([5]="123" [123]="qwe" [4567]="asd")
bash-5.1$ echo "${#a[@]}"
3
3
是數組中元素的數量,但不是您需要的最高鍵值:
bash-5.1$ keys=("${!a[@]}")
bash-5.1$ echo "${keys[@]: -1}"
4567
因此,如果您想列印對齊的鍵和值,您需要類似的東西
printarray() {
local -n arr="$1"
local -a keys=("${!arr[@]}")
local highest_key="${keys[@]: -1}"
local key_width="${#highest_key}"
local key
for key in "${keys[@]}"; do
printf '%*d %s\n' "$key_width" "$key" "${arr[key]}"
done
}
bash-5.1$ printarray a
5 123
123 qwe
4567 asd
(不適用於 Macos 上的古老 bash;local -n
需要 bash 4.3 或更高版本)
¹${#$#array}
不起作用,因為它被視為,即使用Korn 風格運算符從其開頭剝離後${#${$#array}}
的長度。$$
array
${var#pattern}
答案2
正如您所說,這會是某種 BASH 巫術嗎? - 沒有額外的變量
: $((${#pkglist[*]}-1)); echo ${#_};
,但 $_ 可能會導致調試問題 - 長腳本
答案3
編輯:我道歉;正如 @ilkkachu 善意提醒我的那樣,獲取變數長度的最簡單方法是使用${#variable}
,而不是使用外部工具。請忽略這個答案;我很快就會刪除它。我真丟臉!
要確定數字有多少位,您可以使用該數字以 10 為底的對數加一,然後去掉小數部分,但二進制計算器bc
有一個方便的函數可以做到這一點:
echo "length(334344)" | bc
將根據需要列印 6。如果 的參數length
不是整數,它將計算不含小數逗號的實際位數(即,length(3.4560)
將給出 5)。
echo
要在雙引號內使用Bash 變數擴充插入 Bash 變數:
x=334344
echo "length($x)" | bc
我們可以將其寫成一個函數以便於呼叫:
function num_digits {
#determine hoy many digits has a number
#param number
local number="$1"
echo "length($number)" | bc
}
然後按如下方式使用它:
lendigits=$(num_digits 334344)
或者,用一個變數
x=334344
lendigits=$(num_digits $x)
筆記:如果bc
您的 Linux 發行版中尚未安裝,您可以使用發行版的套件管理器來新增它。
筆記2:當然,您可以直接使用表達式而不使用函數:
x=334344
lendigits=$(echo "length($x)" | bc)
但可讀性較差,我更喜歡稍微長一點的腳本,其中識別特殊操作並將其封裝在一個函數中,稍後我可以複製該函數以在其他腳本中使用。