使用字符串替换在 bash 中声明变量名称(不是值)
Declaring a variable name (not value) in bash with string substitution
我有一组变量,如果在我稍后阅读的数组中找到匹配项,我需要在循环中修改其值。数组元素是变量名的子字符串,所以我想写一个通用的 for 循环,它会即时修改变量值,尝试在变量名中进行字符串替换,但这不起作用。
这是代码:
CUT_APPLE=false
CUT_GUAVA=false
CUT_MANGO=false
AVAILABLE_FRUITS=("APPLE" "GUAVA")
for i in "${AVAILABLE_FRUITS[@]}"; do
CUT_$i=true
done
**CUT_APPLE=true: command not found**
**CUT_GUAVA=true: command not found**
有什么方法可以使变量名声明中的插值起作用吗?
如果您的 Bash 版本大于 4,它支持关联数组,这使得检查布尔键是否存在变得容易:
#!/usr/bin/env bash
# Associative array to store keys of available fruits
declare -A cut_fruit=()
declare -a available_fruits=('APPLE' 'GUAVA' 'RED BANANA')
for fruit in "${available_fruits[@]}"; do
# Create key for fruit in Associative array if available
# shellcheck disable=SC2034 # cut_fruit is indeed used
cut_fruit[$fruit]=
done
# Check if cut fruit is available by checking key existence
for fruit in 'APPLE' 'BANANA' 'RED BANANA' 'MANGO'; do
if [[ -v cut_fruit[$fruit] ]]; then
printf 'Cut %s is available.\n' "$fruit"
else
printf 'There is no cut %s.\n' "$fruit"
fi
done
示例输出:
Cut APPLE is available.
There is no cut BANANA.
Cut RED BANANA is available.
There is no cut MANGO.
这是一个使用关联数组键和布尔检查来玩的小游戏:
#!/usr/bin/env bash
print_basket() {
# Print remaining keys (content of basket)
for fruit in "${!basket[@]}"; do
printf '%d %s\n' "${basket[$fruit]}" "${fruit,,}"
done
}
cat <<'EOF'
--:{# Guess the fruits in my basket #}:--
EOF
declare -a all_fruits=(
'apple' 'banana' 'cherry' 'lemon' 'mango'
'orange' 'peach' 'plum' 'red banana' 'sweat chestnut')
# Number of fruits in the basked
selection_size=3
declare -a fruits_selection
mapfile -t fruits_selection < <(
# Shuffle a selection of fruits
printf '%s\n' "${all_fruits[@]}" | shuf -n "$selection_size"
)
declare -A basket
# Set selected fruits into basked
for fruit in "${fruits_selection[@]}"; do
# Uppercase the key for case insensitive match later
basket[${fruit^^}]=$((RANDOM % 9 + 1))
done
# Cheating
declare -p basket
max_tries=3
tries_left=$max_tries
guessed=0
while [ $guessed -lt $selection_size ] && [ $tries_left -gt 0 ]; do
printf 'Enter the name of a fruit: '
read -r fruit
# Uppercase fruit for case insensitive match
fruit="${fruit^^}"
if [[ -v basket[$fruit] ]]; then
printf 'Yes, there is %d %s in my basket!\n' \
"${basket[$fruit]}" "${fruit,,}"
guessed=$((guessed + 1))
# Remove fruit from basket
unset "basket[$fruit]"
else
tries_left=$((tries_left - 1))
printf 'No, there is no %s in my basket!\nTries left: %d\n' \
"${fruit,,}" "$tries_left"
fi
done
case $guessed in
"$selection_size")
printf '* * * Congratulations, you guessed all fruilts! * * *\n'
;;
0)
printf 'Sorry you could not guess any of the fruits!\nBasket contained:\n'
print_basket
;;
*)
printf 'Nice! You guessed %d fruits out of %s!\nUnguessed fruits:\n' \
"$guessed" "$selection_size"
print_basket
;;
esac
我有一组变量,如果在我稍后阅读的数组中找到匹配项,我需要在循环中修改其值。数组元素是变量名的子字符串,所以我想写一个通用的 for 循环,它会即时修改变量值,尝试在变量名中进行字符串替换,但这不起作用。 这是代码:
CUT_APPLE=false
CUT_GUAVA=false
CUT_MANGO=false
AVAILABLE_FRUITS=("APPLE" "GUAVA")
for i in "${AVAILABLE_FRUITS[@]}"; do
CUT_$i=true
done
**CUT_APPLE=true: command not found**
**CUT_GUAVA=true: command not found**
有什么方法可以使变量名声明中的插值起作用吗?
如果您的 Bash 版本大于 4,它支持关联数组,这使得检查布尔键是否存在变得容易:
#!/usr/bin/env bash
# Associative array to store keys of available fruits
declare -A cut_fruit=()
declare -a available_fruits=('APPLE' 'GUAVA' 'RED BANANA')
for fruit in "${available_fruits[@]}"; do
# Create key for fruit in Associative array if available
# shellcheck disable=SC2034 # cut_fruit is indeed used
cut_fruit[$fruit]=
done
# Check if cut fruit is available by checking key existence
for fruit in 'APPLE' 'BANANA' 'RED BANANA' 'MANGO'; do
if [[ -v cut_fruit[$fruit] ]]; then
printf 'Cut %s is available.\n' "$fruit"
else
printf 'There is no cut %s.\n' "$fruit"
fi
done
示例输出:
Cut APPLE is available.
There is no cut BANANA.
Cut RED BANANA is available.
There is no cut MANGO.
这是一个使用关联数组键和布尔检查来玩的小游戏:
#!/usr/bin/env bash
print_basket() {
# Print remaining keys (content of basket)
for fruit in "${!basket[@]}"; do
printf '%d %s\n' "${basket[$fruit]}" "${fruit,,}"
done
}
cat <<'EOF'
--:{# Guess the fruits in my basket #}:--
EOF
declare -a all_fruits=(
'apple' 'banana' 'cherry' 'lemon' 'mango'
'orange' 'peach' 'plum' 'red banana' 'sweat chestnut')
# Number of fruits in the basked
selection_size=3
declare -a fruits_selection
mapfile -t fruits_selection < <(
# Shuffle a selection of fruits
printf '%s\n' "${all_fruits[@]}" | shuf -n "$selection_size"
)
declare -A basket
# Set selected fruits into basked
for fruit in "${fruits_selection[@]}"; do
# Uppercase the key for case insensitive match later
basket[${fruit^^}]=$((RANDOM % 9 + 1))
done
# Cheating
declare -p basket
max_tries=3
tries_left=$max_tries
guessed=0
while [ $guessed -lt $selection_size ] && [ $tries_left -gt 0 ]; do
printf 'Enter the name of a fruit: '
read -r fruit
# Uppercase fruit for case insensitive match
fruit="${fruit^^}"
if [[ -v basket[$fruit] ]]; then
printf 'Yes, there is %d %s in my basket!\n' \
"${basket[$fruit]}" "${fruit,,}"
guessed=$((guessed + 1))
# Remove fruit from basket
unset "basket[$fruit]"
else
tries_left=$((tries_left - 1))
printf 'No, there is no %s in my basket!\nTries left: %d\n' \
"${fruit,,}" "$tries_left"
fi
done
case $guessed in
"$selection_size")
printf '* * * Congratulations, you guessed all fruilts! * * *\n'
;;
0)
printf 'Sorry you could not guess any of the fruits!\nBasket contained:\n'
print_basket
;;
*)
printf 'Nice! You guessed %d fruits out of %s!\nUnguessed fruits:\n' \
"$guessed" "$selection_size"
print_basket
;;
esac