Значение этого ответа заключается в объяснении проблемы с кодом OP.
- Другие ответы показывают использование Bash v4 + встроенный mapfile
(или его эффективный псевдоним, readarray
) для непосредственного чтения ввода строки за строкой в элементы массива без необходимости использования специальной функции оболочки.
- В Bash v3.x вы можете использовать IFS=$'\n' read -r -d '' -a lines < <(...),
, но учтите, что пустые строки будут игнорироваться.
Ваша основная проблема заключается в том, что неупомянуто (без двойных кавычек) использование $1
делает оболочку применять word-splitting на его содержание, которое эффективно нормализует все пробеги пробельного - включая переводы строки - в одном пространстве каждый, в результате чего вводится входная линия в петлю while
.
Во-вторых, с использованием $input
неупоставленного применяется это слово-разделение снова на выходе с echo
.
Наконец, с помощью read
без установки $IFS
, внутренний разделитель полей, пустая строка - через IFS= read -r line
- начальные и конечные пробелы отделан из каждой входной линии.
Тем не менее, вы можете упростить функцию для чтения непосредственно из стандартного ввода, а не принимать аргументы:
function get_lines {
while IFS= read -r line; do
printf '%s\n' "$line"
done
}
который можно затем вызвать следующим образом, используя process substitution:
get_lines < <(loginctl list-sessions)
Использование трубопровод тоже будет работать, но get_lines
будет работать в подоболочке, что означает, что он не может установить переменные, видимые для текущего оболочки:
loginctl list-sessions | get_lines
++, но вы должны добавить '-t' так, чтобы не захватить завершающую' \ n' вместе с каждой входной линией; 'readarray' требует Bash 4.x. – mklement0
Выглядит отлично. Я не получаю '<<(' part. Что он делает? – 8thperson