(Bash) Редактирование содержимого массив из функции

Вы можете использовать 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}"
4
13.06.2018, 15:26
6 ответов

Только для вывода:

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здесь дополнительно позволяет вам выбрать количество отступов.

Массив передается по имени и принимается функцией в переменной-ссылке имени. Это означает, что всякий раз, когда в функции осуществляется доступ к ссылке на имя, фактически используется именованная переменная.

6
27.01.2020, 20:47

Вы делаете две ошибки.

  1. Вы передаете testArrayв функцию, затем создаете новый массив в функции, модифицируете его, но в конце концов распечатываете первый массив. Вы хотите распечатать измененные результаты, верно?

  2. Ваш скрипт не делает того, что вы ожидаете, потому что вы используете эту конструкцию:

     array[$counter]=${array[$counter]/%/$l16}
    

    Это замена шаблона общей формы ${parameter/pattern/string}. Вам не нужно ничего заменять. К этому моменту у вас уже готов суффикс, просто нужно добавить его, например:

    array[$counter]="${array[$counter]}${l16}"
    

Вы можете получить доступ к массиву arrayвне функции, так как массив не объявлен как локальный. Так что вы можете просто использовать:

echo -e "${array[0]}"

и т. д.

1
27.01.2020, 20:47

Если переключение на 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.

4
27.01.2020, 20:47

Чтобы передавать переменные по ссылке в bash4.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 -nnameref заимствована из ksh93, однако обратите внимание, что в отличие от ksh93описанная выше функция не будет работать для заполнения переменных массива, имя которых используется в функции (, поэтому символ подчеркивания префикс для них, чтобы ограничить риск столкновения ).

1
27.01.2020, 20:47

Если вы хотите установить произвольный верхний предел на количество пробелов, чтобы добавить (и вы, очевидно, поскольку ваш оператор caseне может обрабатывать длину больше 20 ), а ты говоришь только о байтах (, а не символов , которые могут быть мульти -байтами ), простой способ дополнить переменную до заданной длины:

# 75 spaces
spaces="                                                                           "
    ︙
length=20
    ︙
newValue=$(expr substr "$value$spaces" 1 "$length")
0
27.01.2020, 20:47

Основная идея

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[@]}"
0
27.01.2020, 20:47

Теги

Похожие вопросы