何かを含めたり含めたりできない配列があり、配列BMC
の各要素を繰り返しています。ループの最後の繰り返しになりBMC
たい内容が含まれている場合。BMC
配列はコマンドラインオプションを使用して生成されるため、大きな変更がなければ生成順序を強制できないようです。
例:
#!/usr/bin/env bash
while getopts cnBba opt; do
case $opt in
c) options+=(CPLD);;
n) options+=(NIC);;
B) options+=(BMC);;
b) options+=(BIOS);;
a) all=true;;
esac
done
# This is probably really confusing because it's redacted but this script also
# allows for -a to be used and then I'll query an endpoint that gives me a list
# of all available firmware for the given server. It could return some or all
# of the possible options in no particular order.
mapfile -t types < <(curl some_firmware_endpoint)
if [[ $all == true ]]; then
options=($(printf '%s\n' "${types[@]}" NIC | sort -u))
fi
for opt in "${options[@]}"; do
echo "option is $opt"
done
次の出力が生成されます。
$ ./script.sh -Bbcn
option is BMC
option is BIOS
option is CPLD
option is NIC
しかし、私は次のような出力が欲しいです。
$ ./script.sh -Bbcn
option is BIOS
option is CPLD
option is NIC
option is BMC
解決策がありますが、配列に空の要素が作成されます。さらに処理できると確信していますが、より正確な方法がある可能性があります。
私の解決策:
#!/usr/bin/env bash
while getopts cnBba opt; do
case $opt in
c) options+=(CPLD);;
n) options+=(NIC);;
B) options+=(BMC);;
b) options+=(BIOS);;
a) all=true;;
esac
done
# This is probably really confusing because it's redacted but this script also
# allows for -a to be used and then I'll query an endpoint that gives me a list
# of all available firmware for the given server. It could return some or all
# of the possible options in no particular order.
mapfile -t types < <(curl some_firmware_endpoint)
if [[ $all == true ]]; then
options=($(printf '%s\n' "${types[@]}" NIC | sort -u))
fi
if [[ "${options[@]}" =~ BMC ]]; then
options=("${options[@]/BMC/}" BMC)
fi
for opt in "${options[@]}"; do
echo "option is $opt"
done
次を生成します。
$ ./script.sh -Bbcn
option is
option is BIOS
option is CPLD
option is NIC
option is BMC
-a すべてのオプション:
allオプションは、サーバータイプのファームウェアリストを含むエンドポイント(デフォルトではjsonオブジェクト)を照会します。一部のサーバーではその値のみを返すことも、BIOS BMC
一部のサーバーではBIOS BMC NIC CPLD SATA StorageController
より多くの値を返すこともあります。 jsonオブジェクトの構成方法により、ほとんどはNICファームウェアを別々に一覧表示するため、-aを使用するとそのエラーを手動で追加し、特定のNICのファームウェアがない場合はそのエラーを個別に処理してからその時点から処理します。一部そこにネットワークカードもあります。sort -u
ネットワークカードが2回リストされたら削除します。
答え1
後で配列を作成します。このオプションを使用する場合は、-a
enpointを呼び出してBMC
最後の文字列の並べ替えを使用しますsed
。使用しない場合は、指定されたコマンドラインオプションから配列を作成します。
(注:ここではインデントにリテラルタブを使用しています。ここでは、空白があるとドキュメントが正しく機能しません。または手動でインデントを削除できます。)
#!/bin/bash
# Fake endpoint response.
get_valid () {
cat <<-END_LIST
BIOS
BMC
tiny green peas
CPLD
MICROBE
END_LIST
}
a_opt=false
unset -v c_opt n_opt B_opt b_opt
while getopts acnBb opt; do
case $opt in
a) a_opt=true ;;
c) c_opt=1 ;;
n) n_opt=1 ;;
B) B_opt=1 ;;
b) b_opt=1 ;;
*) : # error handling here
esac
done
if "$a_opt"; then
readarray -t options < <(
get_valid |
sed -e '/^BMC$/{ h; d; }' \
-e '${ p; g; /^$/d; }'
)
else
options=(
${c_opt:+CPLD}
${n_opt:+NIC}
${b_opt:+BIOS}
${B_opt:+BMC}
)
fi
printf 'Option: "%s"\n' "${options[@]}"
Without -a
:options
上記のコードの配列は、割り当てにリストされている順序で各解析オプションに対応する文字列を使用して生成されます。文字列は、その変数が設定されている場合にのみ配列に含まれます_opt
(実際の値は重要ではありません)。
With -a
:options
エンドポイントから返された文字列から配列が生成されます。エンドポイントの出力で対応する文字列が1行にある場合は、最後の行BMC
が処理されるまで予約済みスペースに保存して最後に移動します。
$ bash script -bBcn
Option: "CPLD"
Option: "NIC"
Option: "BIOS"
Option: "BMC"
$ bash script -a
Option: "BIOS"
Option: "tiny green peas"
Option: "CPLD"
Option: "MICROBE"
Option: "BMC"
答え2
特別なケースは特別で、ループ後に手動で追い出すことができます。
...
handle_opt() {
echo "option is $1"
}
do_BMC=0
for opt in "${options[@]}"; do
if [[ $opt = BMC ]]; then do_BMC=1; continue; fi
handle_opt "$opt"
done
if [[ $do_BMC= 1 ]]; then
handle_opt "BMC"
fi
または、オプションが定数配列で処理される順序を変更し、連想配列を使用してどのオプションが有効になっているかを示します。これは、外部プログラムから入力を読み取ることがそれほど単純ではないことを意味しますmapfile
。 (これは Kusalananda の解決策の変形として見ることができます.)
テストされていませんが、次のアイデアを得ることができます。
order=(CPLD BIOS NIC BMC) # keep BMC last
declare -A options # associative array
while getopts cnBba opt; do
case $opt in
c) options[CPLD]=1 ;;
n) options[NIC]=1 ;;
B) options[BMC]=1 ;;
b) options[BIOS]=1 ;;
a) all=true ;;
esac
done
if [[ $all == true ]]; then
while IFS= read -r line; do
options[$line]=1;
done < <(curl some_firmware_endpoint)
fi
for opt in "${order[@]}"; do
if [[ "${options[$opt]}" != 1 ]]; then continue; fi
handle_opt "$opt"
done
答え3
B
オプションを繰り返してから、options[]
後でスカラー変数を使用して入力するとこの結果が得られることに注意してください。
$ cat script.sh
#!/usr/bin/env bash
while getopts cnBba opt; do
case $opt in
c) options+=(CPLD);;
n) options+=(NIC);;
B) gotB=1;;
b) options+=(BIOS);;
a) all=true;;
esac
done
# mapfile and it's associated loop would go here
(( gotB )) && options+=(BMC)
for opt in "${options[@]}"; do
echo "option is $opt"
done
$ ./script.sh -Bbcn
option is BIOS
option is CPLD
option is NIC
option is BMC
$ ./script.sh -bcn
option is BIOS
option is CPLD
option is NIC
あるいは、bashバージョンがそれをサポートしている場合は、-v
別々のオプションの配列を維持し、getopts
そのB
中でインデックス付けをテストすることもできます。
$ cat script.sh
#!/usr/bin/env bash
declare -A opts
while getopts cnBba opt; do
opts["$opt"]=''
case $opt in
c) options+=(CPLD);;
n) options+=(NIC);;
b) options+=(BIOS);;
a) all=true;;
esac
done
# mapfile and it's associated loop would go here
[[ -v opts[B] ]] && options+=(BMC)
for opt in "${options[@]}"; do
echo "option is $opt"
done
または、最初に他の配列の最後に追加したいオプションを保存してから、options[]
その配列に入力します。
$ cat script.sh
#!/usr/bin/env bash
while getopts cnBba opt; do
case $opt in
c) options+=(CPLD);;
n) options+=(NIC);;
B) deferred+=(BMC);;
b) options+=(BIOS);;
a) all=true;;
esac
done
# mapfile and it's associated loop would go here
for opt in "${deferred[@]}"; do
options+=("$opt")
done
for opt in "${options[@]}"; do
echo "option is $opt"
done
コメントで述べたように、上記のスクリプトmapfile
とスクリプトに関連するループを追加します。while getopts
B
options[]
答え4
答えてくれてありがとう。私は結局このように選びました。
#!/usr/bin/env bash
while getopts cnBba opt; do
case $opt in
c) options+=(CPLD);;
n) options+=(NIC);;
B) options+=(BMC);;
b) options+=(BIOS);;
a) all=true;;
esac
done
mapfile -t types < <(curl some_firmware_endpoint)
if [[ $all == true ]]; then
options=($(printf '%s\n' "${types[@]}" NIC | sort -u))
fi
if [[ "${options[@]}" =~ BMC ]]; then
options=("${options[@]/BMC/}" BMC)
fi
for opt in "${options[@]}"; do
[[ -z "$opt" ]] && continue
echo "option is $opt"
done
オプションに含まれている場合は、削除さBMC
れてから最後に読みます。その後、null要素が生成されるため、ループ内でその要素がnullであることを確認し、その反復をスキップします。