Reputation: 417
Here's my bash function to get a command's output as parameter and then return an array of output lines.
function get_lines {
while read -r line; do
echo $line
done <<< $1
}
SESSIONS=`loginctl list-sessions`
get_lines "$SESSIONS"
Actual output of loginctl list-sessions
is:
SESSION UID USER SEAT
c2 1000 asif seat0
c7 1002 sadia seat0
But the while loop only runs once printing all output in a single line. How can I get an array of lines and return it?
Upvotes: 3
Views: 1810
Reputation: 4350
here's a way in bash
v4+:
SESSIONS=`loginctl list-sessions`
mapfile -t myArray <<< "$SESSIONS"
ref:
Creating an array from a text file in BASH with mapfile
Upvotes: 1
Reputation: 440526
The value of this answer is in explaining the problem with the OP's code.
- The other answers show the use of Bash v4+ builtin mapfile
(or its effective alias, readarray
) for directly reading input line by line into the elements of an array, without the need for a custom shell function.
- In Bash v3.x, you can use IFS=$'\n' read -r -d '' -a lines < <(...),
, but note that empty lines will be ignored.
Your primary problem is that unquoted (non-double-quoted) use of $1
makes the shell apply word-splitting to its contents, which effectively normalizes all runs of whitespace - including newlines - to a single space each, resulting in a single input line to the while
loop.
Secondarily, using $input
unquoted applies this word-splitting again on output with echo
.
Finally, by using read
without setting $IFS
, the internal field separator, to the empty string - via IFS= read -r line
- leading and trailing whitespace is trimmed from each input line.
That said, you can simplify your function to read directly from stdin rather than taking arguments:
function get_lines {
while IFS= read -r line; do
printf '%s\n' "$line"
done
}
which you can then invoke as follows, using a process substitution:
get_lines < <(loginctl list-sessions)
Using a pipeline would work too, but get_lines
would then run in a subshell, which means that it can't set variables visible to the current shell:
loginctl list-sessions | get_lines
Upvotes: 1
Reputation: 31
You could use readarray and avoid the get_lines function:
readarray SESSIONS < <(loginctl --no-legend list-sessions)
this create the array SESSIONS
with each line of the output of the command mapped to an element of the array.
Upvotes: 3