проблема с readarray (или pipe)


19

Я застрял со странным поведением readarrayкоманды.

В man bashгласит:

readarray
     Read lines from the standard input into the indexed array variable array

но эти скрипты не работают (массив пуст):

unset arr; (echo a; echo b; echo c) | readarray arr; echo ${#arr[@]}
unset arr; cat /etc/passwd | readarray arr;  echo ${#arr[@]}

И эти работы:

unset arr; readarray arr < /etc/passwd ;  echo ${#arr[@]}
unset arr; mkfifo /tmp/fifo; (echo a; echo b; echo c) > /tmp/fifo & mapfile arr < /tmp/fifo ; echo ${#arr[@]}

Что не так с трубой?

Ответы:


15

Может быть, попробуйте:

unset arr
printf %s\\n a b c | {
    readarray arr
    echo ${#arr[@]}
}

Я ожидаю, что это сработает, но как только вы выйдете из последнего контекста {оболочки ; }в конце |конвейера, вы потеряете значение переменной. Это потому, что каждый из |отдельных |процессов в |конвейере выполняется в (подоболочке ). Так что твоя вещь не работает по той же причине:

( arr=( a b c ) ) ; echo ${arr[@]}

... не - значение переменной было установлено в другом процессе оболочки, чем тот, в котором вы вызываете его.


23

Чтобы readarrayкоманда выполнялась в текущей оболочке, используйте вместо процесса конвейерную подстановку:

readarray arr < <( echo a; echo b; echo c )

или (если bash4.2 или позже) используйте параметр lastpipeоболочки:

shopt -s lastpipe
( echo a; echo b; echo c ) | readarray arr

1
Здорово. Это работает, но что именно подменяет процесс? А что значит иметь < <2 стрелки?
CMCDragonkai

1
Смотрите bashсправочную страницу. Короче говоря, это синтаксис для обработки конвейера как дескриптора файла. < <(...)означает перенаправить ввод (первый <) с выхода команды внутрь <(...). Аналогично, > >(...)стандартный вывод передается на стандартный ввод внутри конвейера >(...). Вам не обязательно использовать перенаправление с заменой процесса. cat <( echo a b c )работает так же.
Чепнер

Обе эти опции приводят к нежелательному результату для меня, когда каждый элемент массива сохраняет окончания строк в конце каждой строки. Принимая во внимание, что ответ smac89 не имеет этой проблемы.
thnee

3

readarray также можно читать со стандартного ввода, так что

readarray arr <<< "$(echo a; echo b; echo c)"; echo ${#arr[@]}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.