무언가를 포함하거나 포함하지 않을 수 있는 배열이 있고 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
네트워크 카드가 두 번 나열되면 삭제하겠습니다.
답변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
끝점에서 반환된 문자열에서 배열이 생성됩니다. 엔드포인트의 출력에서 해당 문자열이 한 줄에 있는 경우 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인지 확인하고 해당 반복을 건너뜁니다.