LINUX.ORG.RU

bash: из функции получить массив строк, содержащих пробелы, как?

 , ,


1

1

Пример кода:

array(){
    arr[${#arr[@]}]="12 3"
    arr[${#arr[@]}]="54 3 4"
    echo "${arr[@]}"
}

values=( `array` )

echo ${values[@]}
echo ${#values[@]}

Пишет 5 элементов. Как сделать, чтоб получилось 2?



Последнее исправление: cetjs2 (всего исправлений: 1)

Ответ на: help от rdd462

1) Другой язык, 2) глобальный массив, 3) printf '%s\n' в функции и readarray ... < <(array) на месте вызова.

anonymous
()
Ответ на: help от rdd462

из функции убрать echo ...

функцию вызвать

array
value=("${arr[@]}")

sdio ★★★★★
()
Последнее исправление: sdio (всего исправлений: 1)
Ответ на: комментарий от anonymous

А, блин, вариан попроще, чем 3) забыл: IFS=$'\n' перед вызовом.

anonymous
()
Ответ на: help от rdd462

1) Почитайте о declare -p.

Вы можете сформировать массив в функции, вывести его декларацию как результат выполнения функции и применить эту декларацию обычным source <(выхлоп_функции) или eval «$(функция)».

2) Второй вариант - использовать глобальные переменные (самый очевидный, но безусловно весьма неопрятный/нечистоплотный во всех отношениях)

3) Всякие readarray тоже вполне адекватны задаче, но способ с declare -p гораздо менее чреват багами, поскольку declare -p гарантированно создаёт описание массива, применимое для клонирования оного

На баше так функции не используют

Используют. Если есть гарантия того, что вывод функции содержит IFS только как разделитель элементов массива, а внутри элементов IFS'а нет, то можно и так - вполне адекватный метод. Ну и да, ничто не мешает временно поменять IFS, а потом вернуть его значение.

DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)

Да, чуть не забыл!

Вместо:

 arr[${#arr[@]}]="12 3"
 arr[${#arr[@]}]="54 3 4"

Я бы сделал что-то вроде этого:

arr+=('12 3' '54 3 4')

Во-первых двойные кавычки в BASH используются для интерполяции, и если интерполировать нечего, то одинарные не только быстрее, но и безопаснее.

Во-вторых - ну да, есть такая конструкция: list+=(new_el1 new_el2 new_elN), делающая то же, что и, например, push в «более других» языках программирования.

DRVTiny ★★★★★
()
Ответ на: комментарий от DRVTiny
list+=(new_el1 new_el2)

не подойдет, так как я использую добавление новых элементов в цикле.

1)Глобальный массив не подходит, так как его значение нужно присваивать разным переменным (иначе для чего функция?). 2)С declare -p работать потом приходится так же, как с глобальным массивом.

выходом для этих двух способов является конструкция, предложенная вами где-то..:

eval "$(aa)"
t="$(declare -p arr)"
eval ${t/declare -a arr/declare -a value}

так работает, но громоздко как-то..

rdd462
() автор топика
Ответ на: комментарий от rdd462

не подойдет, так как я использую добавление новых элементов в цикле.

Так лучше?

list+=(new_el)

DRVTiny ★★★★★
()
Ответ на: комментарий от rdd462

так работает, но громоздко как-то..

Передавайте имя создаваемой глобальной переменной прямо в функцию и там делайте

source <(declare -p arr | sed "s%^declare -a array1%declare -a $arrName%")

Не спорю, что и эта конструкция выглядит уродливо,но тут уж на безжирье и рак - жирный :)

DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)

Как-то так.

array() {
    arr[${#arr[@]}]="12 3"
    arr[${#arr[@]}]="54 3 4"
    printf '%s\0' "${arr[@]}"
}

values=()

while IFS= read -rd '' element; do
    values=( "${values[@]}" "${element}" )
done < <(array)

echo "${values[@]}"
echo "${#values[@]}"
anonymous
()

М-да, фигня этот ваш баш.

; subfn array {
	result = ('12 3' '54 3 4')
	for i in a b c { result = $result $i }
}
; values = ${array}
; echo $values
12 3 54 3 4 a b c
; echo $#values
5 
korvin_ ★★★★★
()
Ответ на: комментарий от DRVTiny

Чяднт?

array(){
    arr+=("12 3")
    arr+=("54 3 4")
    source <( declare -p arr | sed "s/declare -a arr/declare -a asd/" )
#вместо asd будет имя массива
}

declare -a asd
eval $(array)
declare -p asd

echo ${asd[@]}

Не работает

echo ${arr[@]}

работает

rdd462
() автор топика
Ответ на: комментарий от rdd462

ЗАЧЕМ вы делаете eval, если у вас уже в функци выполняется source?

Всё правильно, но нужно просто вызывать функцию array.

P.S. Чем Вам так нравятся двойные кавычки? Мало того, что они чреваты side-effect'ами, если, конечно, вы их не используете сознательно, так они ещё и вводятся с shift'ом!

DRVTiny ★★★★★
()
Ответ на: комментарий от DRVTiny

doesn't work

Строки прям в кавычках будут приходить, поэтому я их не меняю здесь.

заменил строчку с eval на просто вызов array, продолжает не работать..

Будет замечательно, если заработает именно этот способ, потому что хочется всё спрятать в функцию и в отдельный модуль.

rdd462
() автор топика
Ответ на: doesn't work от rdd462
getArray () {
    arrName=$1
    declare -a arr1=("Puttin\' on the Ritz
the
song")
    arr1+=('dressed up like' 'million dollar trooper')
    arr1+=('trying hard' 'to look like Gary Cooper')
    declare -p arr1 | sed "s/declare -a arr1/declare -a $arrName/"
}
source <(getArray arr2)
declare -p arr2

Да, чуть не забыл: https://en.wikipedia.org/wiki/Gary_Cooper

DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)

строк, содержащих пробелы

bash

для начала, перейти на perl

MyTrooName ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.