Reputation: 1422
I have a file called failedfiles.txt
with the following content:
failed1
failed2
failed3
I need to use grep to return the content on each line in that file, and save the output in a list to be accessed. So I want something like this:
temp_list=$(grep "[a-z]" failedfiles.txt)
However, the problem with this is that when I type
echo ${temp_list[0]}
I get the following output:
failed1 failed2 failed3
But what I want is when I do:
echo ${temp_list[0]}
to print
failed1
and when I do:
echo ${temp_list[1]}
to print
failed2
Thanks.
Upvotes: 3
Views: 6332
Reputation: 437111
@devnull's helpful answer explains why your code didn't work as expected: command substitution always returns a single string (possibly composed of multiple lines).
However, simply putting (...)
around a command substitution to create an array of lines will only work as expected if the lines output by the command do not have embedded spaces - otherwise, each individual (whitespace-separated) word will become its own array element.
To capture the lines output by an arbitrary command in an array, use the following:
read -a
IFS=$'\n' read -rd '' -a linesArray <<<"$(grep "[a-z]" failedfiles.txt)"
readarray
:readarray -t linesArray <<<"$(grep "[a-z]" failedfiles.txt)"
Note:
<<<
initiates a so-called here-string, which pipes the string to its right (which happens to be the result of a command substitution here) into the command on the left via stdin
.
command <<< string
is functionally equivalent to echo string | command
in principle, the crucial difference is that the latter creates subshells, which make variable assignments in command
pointless - they are localized to each subshell.<(...)
- which, simply put, allows using a command's output as if it were an input file; the equivalent of <<<"$(command)"
is < <(command)
.read
: -a
reads into an array, and IFS=$'\n'
ensures that every line is considered a separate field and thus read into its own array element; -d ''
ensures that ALL lines are read at once (before breaking them into fields); -r
turns interpretation of escape sequence in the input off.readarray
(also callable as mapfile
) directly breaks input lines into an array of lines; -t
ensures that the terminating \n
is NOT included in the array elements.If there is no need to capture all lines in an array at once and looping over a command's output line by line is sufficient, use the following:
while IFS= read -r line; do
# ...
done < <(grep "[a-z]" failedfiles.txt)
IFS=
ensures that each line is read unmodified in terms of whitespace; remove it to have leading and trailing whitespace trimmed.-r
ensures that the lines are read 'raw' in that substrings in the input that look like escape sequences - e.g., \t
- are NOT interpreted as such.read
loop.Upvotes: 12
Reputation: 189317
The proper and portable way to loop over lines in a file is simply
while read -r line; do
... something with "$line"
done <failedfiles.txt
Upvotes: 2
Reputation: 123458
You did not create an array. What you did was Command Substitution which would simply put the output of a command into a variable.
In order to create an array, say:
temp_list=( $(grep "[a-z]" failedfiles.txt) )
You might also want to refer to Guide on Arrays.
Upvotes: 3