This question already has an answer here:
这个问题已经有了答案:
- Creating an array from a text file in Bash 6 answers
- 在Bash 6应答中从文本文件创建数组
I am trying to read a file containing lines into a Bash array.
我试图将包含行的文件读入Bash数组。
I have tried the following so far:
到目前为止,我已经尝试了以下步骤:
Attempt1
a=( $( cat /path/to/filename ) )
Attempt2
index=0
while read line ; do
MYARRAY[$index]="$line"
index=$(($index+1))
done < /path/to/filename
Both attempts only return a one element array containing the first line of the file. What am I doing wrong?
两次尝试都只返回包含文件第一行的一个元素数组。我做错了什么?
I am running bash 4.1.5
我正在运行bash 4.1.5
6 个解决方案
#1
91
Latest revision based on comment from BinaryZebra's comment and tested here. The addition of command eval
allows for the expression to be kept in the present execution environment while the expressions before are only held for the duration of the eval.
基于BinaryZebra评论的最新修订并在此进行测试。添加命令eval允许表达式保存在当前执行环境中,而之前的表达式仅在eval期间保存。
Use $IFS that has no spaces\tabs, just newlines/CR
使用没有空格\制表符、只有换行/CR的$IFS
$ IFS=$'\r\n' GLOBIGNORE='*' command eval 'XYZ=($(cat /etc/passwd))'
$ echo "${XYZ[5]}"
sync:x:5:0:sync:/sbin:/bin/sync
Also note that you may be setting the array just fine but reading it wrong - be sure to use both double-quotes ""
and braces {}
as in the example above
还要注意,您可能设置的很好,但是读错了——请确保在上面的示例中同时使用双引号“”和大括号{}
Edit:
编辑:
Please note the many warnings about my answer in comments about possible glob expansion, specifically gniourf-gniourf's comments about my prior attempts to work around
请注意在关于glob扩展的评论中关于我的回答的许多警告,特别是gniourf-gniourf -gniourf关于我之前的工作尝试的评论
With all those warnings in mind I'm still leaving this answer here (yes, bash 4 has been out for many years but I recall that some macs only 2/3 years old have pre-4 as default shell)
考虑到所有这些警告,我仍然在这里留下这个答案(是的,bash 4已经存在多年,但我记得,一些只有2/3岁的mac电脑有4岁之前的默认shell)
Other notes:
另注:
Can also follow drizzt's suggestion below and replace a forked subshell+cat with
也可以按照下面drizzt的建议来替换一个分叉的子shell+cat吗
$(</etc/passwd)
The other option I sometimes use is just set IFS into XIFS, then restore after. See also Sorpigal's answer which does not need to bother with this
我有时使用的另一个选项是将IFS设置为XIFS,然后恢复。参见Sorpigal的答案,不需要为此费心
#2
162
The readarray
command (also spelled mapfile
) was introduced in bash 4, I believe.
在bash 4中引入了readarray命令(也拼写了mapfile)。
readarray a < /path/to/filename
#3
79
The simplest way to read each line of a file into a bash
array is this:
将文件的每一行读入bash数组的最简单方法是:
IFS=$'\n' read -d '' -r -a lines < /etc/passwd
Now just index in to the array lines
to retrieve each line, e.g.
现在只需索引数组行来检索每一行,例如。
printf "line 1: %s\n" "${lines[0]}"
printf "line 5: %s\n" "${lines[4]}"
# all lines
echo "${lines[@]}"
#4
17
One alternate way if file contains strings without spaces with 1string each line:
如果文件包含没有空格的字符串,每行都有1string,有一种替代方法:
fileItemString=$(cat filename |tr "\n" " ")
fileItemArray=($fileItemString)
Check:
检查:
Print whole Array:
打印整个数组:
${fileItemArray[*]}
Length=${#fileItemArray[@]}
#5
6
Your first attempt was close. Here is the simplistic approach using your idea.
你的第一次尝试很接近。这是使用你的想法的简单方法。
file="somefileondisk"
lines=`cat $file`
for line in $lines; do
echo "$line"
done
#6
2
#!/bin/bash
IFS=$'\n' read -d'' -r -a inlines < testinput
IFS=$'\n' read -d'' -r -a outlines < testoutput
counter=0
cat testinput | while read line;
do
echo "$((${inlines[$counter]}-${outlines[$counter]}))"
counter=$(($counter+1))
done
# OR Do like this
counter=0
readarray a < testinput
readarray b < testoutput
cat testinput | while read myline;
do
echo value is: $((${a[$counter]}-${b[$counter]}))
counter=$(($counter+1))
done
#1
91
Latest revision based on comment from BinaryZebra's comment and tested here. The addition of command eval
allows for the expression to be kept in the present execution environment while the expressions before are only held for the duration of the eval.
基于BinaryZebra评论的最新修订并在此进行测试。添加命令eval允许表达式保存在当前执行环境中,而之前的表达式仅在eval期间保存。
Use $IFS that has no spaces\tabs, just newlines/CR
使用没有空格\制表符、只有换行/CR的$IFS
$ IFS=$'\r\n' GLOBIGNORE='*' command eval 'XYZ=($(cat /etc/passwd))'
$ echo "${XYZ[5]}"
sync:x:5:0:sync:/sbin:/bin/sync
Also note that you may be setting the array just fine but reading it wrong - be sure to use both double-quotes ""
and braces {}
as in the example above
还要注意,您可能设置的很好,但是读错了——请确保在上面的示例中同时使用双引号“”和大括号{}
Edit:
编辑:
Please note the many warnings about my answer in comments about possible glob expansion, specifically gniourf-gniourf's comments about my prior attempts to work around
请注意在关于glob扩展的评论中关于我的回答的许多警告,特别是gniourf-gniourf -gniourf关于我之前的工作尝试的评论
With all those warnings in mind I'm still leaving this answer here (yes, bash 4 has been out for many years but I recall that some macs only 2/3 years old have pre-4 as default shell)
考虑到所有这些警告,我仍然在这里留下这个答案(是的,bash 4已经存在多年,但我记得,一些只有2/3岁的mac电脑有4岁之前的默认shell)
Other notes:
另注:
Can also follow drizzt's suggestion below and replace a forked subshell+cat with
也可以按照下面drizzt的建议来替换一个分叉的子shell+cat吗
$(</etc/passwd)
The other option I sometimes use is just set IFS into XIFS, then restore after. See also Sorpigal's answer which does not need to bother with this
我有时使用的另一个选项是将IFS设置为XIFS,然后恢复。参见Sorpigal的答案,不需要为此费心
#2
162
The readarray
command (also spelled mapfile
) was introduced in bash 4, I believe.
在bash 4中引入了readarray命令(也拼写了mapfile)。
readarray a < /path/to/filename
#3
79
The simplest way to read each line of a file into a bash
array is this:
将文件的每一行读入bash数组的最简单方法是:
IFS=$'\n' read -d '' -r -a lines < /etc/passwd
Now just index in to the array lines
to retrieve each line, e.g.
现在只需索引数组行来检索每一行,例如。
printf "line 1: %s\n" "${lines[0]}"
printf "line 5: %s\n" "${lines[4]}"
# all lines
echo "${lines[@]}"
#4
17
One alternate way if file contains strings without spaces with 1string each line:
如果文件包含没有空格的字符串,每行都有1string,有一种替代方法:
fileItemString=$(cat filename |tr "\n" " ")
fileItemArray=($fileItemString)
Check:
检查:
Print whole Array:
打印整个数组:
${fileItemArray[*]}
Length=${#fileItemArray[@]}
#5
6
Your first attempt was close. Here is the simplistic approach using your idea.
你的第一次尝试很接近。这是使用你的想法的简单方法。
file="somefileondisk"
lines=`cat $file`
for line in $lines; do
echo "$line"
done
#6
2
#!/bin/bash
IFS=$'\n' read -d'' -r -a inlines < testinput
IFS=$'\n' read -d'' -r -a outlines < testoutput
counter=0
cat testinput | while read line;
do
echo "$((${inlines[$counter]}-${outlines[$counter]}))"
counter=$(($counter+1))
done
# OR Do like this
counter=0
readarray a < testinput
readarray b < testoutput
cat testinput | while read myline;
do
echo value is: $((${a[$counter]}-${b[$counter]}))
counter=$(($counter+1))
done