2016-05-25 3 views
2

Вот моя функция bash, чтобы получить вывод команды в качестве параметра, а затем вернуть массив выходных строк.вывод команды разделения в массив строк

function get_lines { 
    while read -r line; do 
     echo $line 
    done <<< $1 
} 

SESSIONS=`loginctl list-sessions` 
get_lines "$SESSIONS" 

Фактический выход loginctl list-sessions является:

SESSION  UID USER    SEAT    
     c2  1000 asif    seat0   
     c7  1002 sadia   seat0   

Но цикл, пока работает только один раз печать всех выходных данных в одной строке. Как я могу получить массив строк и вернуть его?

ответ

1

Значение этого ответа заключается в объяснении проблемы с кодом 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 
2

Вы можете использовать readarray и избежать функций get_lines:

readarray SESSIONS < <(loginctl --no-legend list-sessions) 

это создать массив SESSIONS с каждой строкой вывода команды отображенной на элемент массива.

+0

++, но вы должны добавить '-t' так, чтобы не захватить завершающую' \ n' вместе с каждой входной линией; 'readarray' требует Bash 4.x. – mklement0

+0

Выглядит отлично. Я не получаю '<<(' part. Что он делает? – 8thperson

Смежные вопросы