Вы можете использовать declare
с динамическими именами и значениями, а также косвенное обращение к переменным для ссылки на переменные на основе их имени. printf '% q'
может помочь вам в значениях "экранирования оболочки", чтобы их можно было использовать во время динамического присваивания.
#!/bin/bash
declare -a products=( phone computer )
printf 'Product: %s\n' "${products[@]}"
# Product: phone
# Product: computer
unset products
declare varName='products'
declare -a "${varName}"='( cell\ phone laptop\ computer )'
declare arrayRef="${varName}[@]"
printf 'Product: %s\n' "${!arrayRef}"
# Product: cell phone
# Product: laptop computer
unset "${varName}"
declare -a toCopy=( 'LED TV' '"Smart" car' )
declare -a "${varName}"="( $( printf '%q ' "${toCopy[@]}" ) )"
printf 'Product: %s\n' "${!arrayRef}"
# Product: LED TV
# Product: "Smart" car
unset "${varName}"
Только для вывода:
array=( bish bash bosh )
printf '%-20s#\n' "${array[@]}"
Это даст
bish #
bash #
bosh #
... где #
встречается в столбце 21.
Создание нового массива (и его печать):
array=( bish bash bosh )
for elem in "${array[@]}"; do
padarr+=( "$( printf '%-20s#' "$elem" )" )
done
printf '%s\n' "${padarr[@]}"
При /bin/sh
просто печать:
set -- bish bash bosh
printf '%-20s#\n' "$@"
С помощью /bin/sh
, изменив $@
на -вместо:
set -- bish bash bosh
i=0
while [ "$i" -lt "$#" ]; do
set -- "$@" "$( printf '%-20s#' "$1" )"
shift
i=$(( i + 1 ))
done
printf '%s\n' "$@"
Строка форматирования printf
%-20s
резервирует 20 символов для строки -, выровненной по левому краю.
Какbash
(4.3+ )функция:
pad_array () {
local padlen=$1
local -n localarray=$2
local -a tmp
local elem
for elem in "${localarray[@]}"; do
tmp+=( "$( printf '%-*s#' "$padlen" "$elem" )" )
done
localarray=( "${tmp[@]}" )
}
myarray=( bish bash bosh )
pad_array 20 myarray
printf '%s\n' "${myarray[@]}"
Функция pad_array
здесь дополнительно позволяет вам выбрать количество отступов.
Массив передается по имени и принимается функцией в переменной-ссылке имени. Это означает, что всякий раз, когда в функции осуществляется доступ к ссылке на имя, фактически используется именованная переменная.
Вы делаете две ошибки.
Вы передаете testArray
в функцию, затем создаете новый массив в функции, модифицируете его, но в конце концов распечатываете первый массив. Вы хотите распечатать измененные результаты, верно?
Ваш скрипт не делает того, что вы ожидаете, потому что вы используете эту конструкцию:
array[$counter]=${array[$counter]/%/$l16}
Это замена шаблона общей формы ${parameter/pattern/string}
. Вам не нужно ничего заменять. К этому моменту у вас уже готов суффикс, просто нужно добавить его, например:
array[$counter]="${array[$counter]}${l16}"
Вы можете получить доступ к массиву array
вне функции, так как массив не объявлен как локальный. Так что вы можете просто использовать:
echo -e "${array[0]}"
и т. д.
Если переключение на zsh
является опцией:
$ array=(foo bar bàz '')
$ padded_array=(${(r:20:)array})
$ printf '<%s>\n' $padded_array
<foo >
<bar >
<bàz >
< >
Обратите внимание, что этот (r:20:)
правый -параметр заполнения заполняет флаг расширения, но также усекает до 20 символов для более длинных строк.
Другой вариант с zsh
— сделать:
padded_array=()
(($#array)) && printf -v padded_array '%-20s' "$array[@]"
В отличие от bash
, заполнение выполняется по символам -, а не по байтам -, и zsh
поддерживает аргументы массива для опции -v
.
Обратите внимание, что если $array
содержит только один элемент, $padded_array
преобразуется в скаляр.
Для заполнения+усечения замените %-20s
на %-20.20s
.
Чтобы передавать переменные по ссылке в bash
4.3+, вы можете использоватьtypeset -n
:
pad_array() {
typeset -n _array="$1"
typeset _n="$2" _pad _i
printf -v _pad '%*s' "$_n"
for _i in "${!_array[@]}"; do
((${#_array[_i]} < _n)) || continue # remove this line to also truncate
_array[_i]+=$_pad
_array[_i]=${_array[_i]:0:_n}
done
}
array=(foo b bàz '')
pad_array array 20
Функцияtypeset -n
nameref заимствована из ksh93
, однако обратите внимание, что в отличие от ksh93
описанная выше функция не будет работать для заполнения переменных массива, имя которых используется в функции (, поэтому символ подчеркивания префикс для них, чтобы ограничить риск столкновения ).
Если вы хотите установить произвольный верхний предел на количество пробелов, чтобы добавить (и вы, очевидно, поскольку ваш оператор case
не может обрабатывать длину больше 20 ), а ты говоришь только о байтах (, а не символов , которые могут быть мульти -байтами ), простой способ дополнить переменную до заданной длины:
# 75 spaces
spaces=" "
︙
length=20
︙
newValue=$(expr substr "$value$spaces" 1 "$length")
for elem in "${localarrayname[@]}"; do
localtoarray+=( "$(printf '<%-*.*s>\n' "$p" "$p" "$elem")" )
done
Использование printf для добавления переменного количества пробелов очень просто (звездочка — это количество):
$ printf '<%-*s>' 8 hello ; echo
<hello >
Его можно было даже использовать для удлинения или сокращения строки до подсчета:
$ printf '<%-*.*s>' 8 8 "TestingHello" ; echo
<TestingH>
Используя подстановку переменных, мы можем добавить фиксированную строку к переменной:
$ var=hello
$ printf '<%s>\n' "${var/%/"xxx"}"
<helloxxx>
Это можно расширить до массива значений:
$ var=( hello world test )
$ printf '<%s>\n' "${var[@]/%/"xxx"}"
<helloxxx>
<worldxxx>
<testxxx>
Однако, чтобы добавить в массив переменное количество пробелов, нам нужно использовать цикл.
Мы можем использовать функцию для передачи списка значений (только для печати):
padarray(){ p=$1; shift
for elem; do
printf '<%-*.*s>\n' "$p" "$p" "$elem"
done
}
array=( foo qux quuux alongerstring )
padarray 15 "${array[@]}"
Он печатает:
$./script
<foo >
<qux >
<quuux >
<alongerstringto>
Чтобы передать аргументы в новый массив, используйте массив (s )имена (косвенные):
padarray(){ local p=$1;
local -n localarrayname=$2 localtoarray=$3
localtoarray=()
for elem in "${localarrayname[@]}"; do
localtoarray+=( "$(printf '<%-*.*s>\n' "$p" "$p" "$elem")" )
done
}
array=( foo qux quuux alongerstringtotest )
padarray 12 array paddedarray
printf '%s\n' "${paddedarray[@]}"
Что при выполнении выводит аналогичный результат:
$./script
<foo >
<qux >
<quuux >
<alongerstrin>
Добавление более надежного подсчета дополнительных символов($p
):
p=${1//[!0-9]} # Select only numeric digits.
(( 0<=p && p<=999 )) && return 2 # Return on error. Count out of range.
Заканчиваем этим скриптом:
#!/bin/bash
padarray(){ local p=${1//[!0-9]} # Select only numeric digits.
p=${p:-20} # Make the default count = 20.
local -n localarrayname=$2 localtoarray=$3 # Define indirect (local) array names.
localtoarray=() # Clean the resulting array.
(( 0<=p && p<=999 )) || return 2 # Return on error. Count out of range.
for elem in "${localarrayname[@]}"; do
localtoarray+=( "$(printf '<%-*.*s>\n' "$p" "$p" "$elem")" )
done
}
array=( bash bish bosh "" foo qux quuux "A Longer String To Test" )
padarray 20 array paddedarray
printf '%s\n' "${paddedarray[@]}"