问题
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.
回答1:
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.
回答2:
@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.
Capturing command output lines at once, in an array:
To capture the lines output by an arbitrary command in an array, use the following:
- bash < 4 (e.g., on OSX as of OS X 10.9.2): use
read -a
IFS=$'\n' read -rd '' -a linesArray <<<"$(grep "[a-z]" failedfiles.txt)"
- bash >= 4: use
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 viastdin
.- While
command <<< string
is functionally equivalent toecho string | command
in principle, the crucial difference is that the latter creates subshells, which make variable assignments incommand
pointless - they are localized to each subshell.
- While
- An alternative to combining here-strings with command substitution is [input] process substitution -
<(...)
- 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, andIFS=$'\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 asmapfile
) directly breaks input lines into an array of lines;-t
ensures that the terminating\n
is NOT included in the array elements.
Looping over command output lines:
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.- Note the use of [input] process substitution (explained above) to provide the command output as input to the
read
loop.
回答3:
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
来源:https://stackoverflow.com/questions/22776201/how-to-create-an-array-from-the-lines-of-a-commands-output