LINUX.ORG.RU

Строковые массивы в bash

 


0

1

Вопрос, строковые массивы с bash ведь есть? Вот пытаюсь сделать так, чтобы строки из файла array.list записывались в строковый массив array, а потом вывести их... и не работает. Где ошибка?

#!/bin/bash

i=1
cat array.list | while read str
do
   array["$i"]="$str"
   i=$(($i+1))
done
echo ${array[@]}

★★★★★

Когда тебе на баше нужно писать что-то сложнее однострочника с трубами. То нужно брать Си и писать утилиту.

anonymous
()

Делал примерно так:

arrdelay=($(cat ${ugoid}_ugoira1920x1080.txt | jq -r .delay_msec))

Одна строка - один элемент, но тут пробелов нет в строках.

Radjah ★★★★★
()
readarray -t arr < file.txt

И еще 100500 способов.

В гугле, видать, забанили.

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

Это просто я для примера привёл, на самом деле задача - в цикле обработать все строки, а в массив записать содержимое фрагментов некоторых строк, поэтому нужно использовать array[«$i»]= хотя я подозреваю, что именно в этой строке и ошибка. Трассировка через bash -x показывает, что у меня отрабатывается команда array[$i]= вместо array[1] пробовал и с кавычками, и без кавычек

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

Задача - проверить как работает присваивание элемента строкового массива через array[«$i»]=

sunny1983 ★★★★★
() автор топика
#!/bin/bash

i=1
while read str
do
   array["$i"]="$str"
   i=$(($i+1))
done < array.list
echo ${array[@]}
surefire ★★★
()
Ответ на: комментарий от pinus_nigra

Вообще никак? Тогда вместо bash использовать нужно php или python? Я так не умею. Или всё же можно использовать другие операторы, например заменив массив многострочной переменной? Просто задача - не просто прочитать все строки в массив, а сначала строки обработать, то есть, помещаемая в массив строка сначала помещается в переменную $outstr

sunny1983 ★★★★★
() автор топика

Просто переменные включая массив оказались в контексте subshell`а.

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

Напиши в начале shopt -s lastpipe

Длинное объяснение:

Если написать

#!/bin/bash

#shopt -s lastpipe

echo script PID: $BASHPID

i=1
cat array.list | while read str
do
	echo loop PID: $BASHPID
	array["$i"]="$str"
	i=$(($i+1))
done
echo ${array[@]}

то вывод будет примерно такой:

script PID: 26074
loop PID: 26076
loop PID: 26076
loop PID: 26076

т.е. цикл выполняется в другом процессе. Этот другой процесс получает все данные исходного процесса но изменения в другом процессе не отражаются на исходном процессе.

Иными словами когда bash видит command 1 | command 2, даже если command 2 это встроенная команда оболочки, он запускает два отдельных процесса в дополнение к основному.

Опция lastpipe позволяет ему иногда выполнять command 2 в текущей оболочке, таким образом то, что ты там делаешь, отразится в исходной оболочке, включая изменения значений переменных.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 2)
Ответ на: комментарий от sunny1983

А, сорри, я спросонья криво прочитал. Правильный синтаксис. Только declare не хватает.

pinus_nigra
()

ты хочешь использовать mapfile

ubik
()
Ответ на: комментарий от Legioner

Помнится я уже задавал вопрос по bash на ЛОРе в котором мне ответили, что субшеллы - это плохая практика, но я тогда не придал этому значения.
А конструкция типа

echo ${array[$i]} | awk '{print $2}'
то же работать не будет получается? В ней же присутствует пайп - значит это то же субшелл? Чем её тогда заменить?

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

Помнится я уже задавал вопрос по bash на ЛОРе в котором мне ответили, что субшеллы - это плохая практика, но я тогда не придал этому значения.

Да, лучше постараться переписать код по-другому, без них.

А конструкция типа то же работать не будет получается?

Почему ты думаешь, что она не будет работать? Будет.

В ней же присутствует пайп - значит это то же субшелл? Чем её тогда заменить?

В субшелле нельзя менять переменные. Точней менять можно, но родительский шелл изменения не увидит. А доступ субшелл ко всем переменным имеет (точней к тем их значениям, которые были в момент его порождения).

Никаких проблем с субшелами, как таковыми, нет. Избегать их не нужно. Избегать стоит конкретного варианта - когда тебе нужно в субшелле менять значение, используемое в родительском шелле. Да и то в принципе lastpipe работает, если тебя кроме bash ничего не интересует, наверное можно и не морочить голову.

Legioner ★★★★★
()

меняй коньки, на лыжи / while на for

#!/bin/bash

i=1
for str in $(cat array.list); do
   array["$i"]="$str"
   i=$(($i+1))
done
echo ${array[@]}
echo ${#array[@]}

for i in `seq 0 ${#array[@]}`;do
   echo "$i ${array[$i]}";
done
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.