Бывает, что нужно создавать или заполнять переменные с динамическими именами: item_1, item_2, user_alice и т.д. Вместо eval попробуем использовать встроенный printf -v, который позволяет записать форматированный строковый результат прямо в переменную по имени.
Почему printf -v лучше, чем eval?
безопаснее (без спаивания и выполнения произвольного кода),
дает форматирование (числа, нули, float),
удобно в функциях (можно создавать глобальные переменные через declare -g).
▪️ Базовый пример: простая запись
name="user_alice"
printf -v "$name" "%s" "id=42"
echo "$user_alice"
id=42
Здесь мы записали строку в переменную user_alice без eval.
▪️ Нумерация с форматированием (zero-padding)
for i in {1..5}; do
printf -v "item_%03d" "$i" "val_$i"
done
# показать созданные переменные
for i in {1..5}; do
var="item_$(printf '%03d' "$i")"
echo "$var = ${!var}"
done
item_001 = val_1
item_002 = val_2
printf -v "item_%03d" "$i" "val" - формат имени и значение удобно комбинировать.▪️ Создаем набор конфигов из CSV (пример)
while IFS=, read -r key value; do
# нормализовать имя (латиница, цифры, _)
safe_key=$(echo "$key" | tr -c '[:alnum:]_' '_')
printf -v "cfg_%s" "$safe_key" "%s" "$value"
done <<'CSV'
db.host,localhost
db.port,5432
feature.enable,true
CSV
echo "Host: $cfg_db_host"
echo "Port: $cfg_db_port"
echo "Feature: $cfg_feature_enable"
▪️ Инспекция созданных переменных
# показать все переменные с префиксом cfg_
for v in ${!cfg_*}; do
echo "$v = ${!v}"
done
(indirect expansion) позволяет получить значение переменной по имени.
▪️ Комбинация с declare -n (nameref)
printf -v "user_alice" "%s" "alice@bashtex.com"
ref_var="user_alice"
declare -n userref="$ref_var"
echo "Email via nameref: $userref"
declare -n дает ссылку на переменную, это удобнее, чем постоянно подставлять ${!name}.
▪️ Как избежать проблем с именами переменных. Переменная должна соответствовать правилам имени в bash. Можно валидировать:
sanitize() {
printf '%s' "$1" | sed 's/[^a-zA-Z0-9_]/_/g'
}
raw="user-name@host"
safe=$(sanitize "$raw")
printf -v "$safe" "%s" "value"
Если допустить в имени пробелы или символы ; - printf -v либо даст ошибку, либо поведет себя непредсказуемо.
BashTex 📱 #bash #utils