在Bash中的文本文件中创建一个数组。

时间:2022-06-01 13:33:02

A script takes a URL, parses it for the required fields, and redirects its output to be saved in a file, file.txt. The output is saved on a new line each time a field has been found.

脚本获取一个URL,解析它的所需字段,并将其输出重定向到文件file.txt中。每次找到一个字段时,输出都保存在新行上。

file.txt

A Cat
A Dog
A Mouse 
etc... 

I want to take file.txt and create an array from it in a new script, where every line gets to be its own string variable in the array. So far I have tried:

我想取文件。在新脚本中创建一个数组,其中的每一行都是数组中自己的字符串变量。到目前为止,我尝试过:

#!/bin/bash

filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)

for (( i = 0 ; i < 9 ; i++))
do
  echo "Element [$i]: ${myArray[$i]}"
done

When I run this script, whitespace results in words getting split and instead of getting

当我运行这个脚本时,空格会导致单词被分割而不是获取

Desired output

Element [0]: A Cat 
Element [1]: A Dog 
etc... 

I end up getting this:

我最终得到了这个:

Actual output

Element [0]: A 
Element [1]: Cat 
Element [2]: A
Element [3]: Dog 
etc... 

How can I adjust the loop below such that the entire string on each line will correspond one-to-one with each variable in the array?

如何调整下面的循环,使每行上的整个字符串与数组中的每个变量一一对应?

6 个解决方案

#1


57  

Use the mapfile command:

使用mapfile命令:

mapfile -t myArray < file.txt

The error is using for -- the idiomatic way to loop over lines of a file is:

这个错误是用于——循环文件行数的惯用方法是:

while IFS= read -r line; do echo ">>$line<<"; done < file.txt

See BashFAQ/005 for more details.

详情请参阅BashFAQ/005。

#2


4  

You can do this too:

你也可以这样做:

oldIFS="$IFS"
IFS=$'\n' arr=($(<file))
IFS="$oldIFS"
echo "${arr[1]}" # It will print `A Dog`.

Note:

注意:

Filename expansion still occurs. For example, if there's a line with a literal * it will expand to all the files in current folder. So use it only if your file is free of this kind of scenario.

文件名扩张仍然发生。例如,如果有一行文字*,它将扩展到当前文件夹中的所有文件。因此,只有在您的文件没有这种情况时才使用它。

#3


3  

mapfile and readarray (which are synonymous) are available in Bash version 4 and above. If you have an older version of Bash, you can use a loop to read the file into an array:

在Bash version 4和以上版本中,可以使用mapfile和readarray(它们是同义的)。如果您有一个旧版本的Bash,您可以使用循环将文件读入一个数组:

arr=()
while IFS= read -r line; do
  arr+=("$line")
done < file

In case the file has an incomplete (missing newline) last line, you could use this alternative:

如果文件的最后一行不完整(缺少换行符),您可以使用以下方法:

arr=()
while IFS= read -r line || [[ "$line" ]]  do
  arr+=("$line")
done < file

Related:

相关:

#4


2  

You can simply read each line from the file and assign it to an array.

您可以简单地从文件中读取每一行并将其分配给一个数组。

#!/bin/bash
i=0
while read line 
do
        arr[$i]="$line"
        i=$((i+1))
done < file.txt

#5


0  

Use mapfile or read -a

Always check your code using shellcheck. It will often give you the correct answer. In this case SC2207 covers reading a file that either has space separated or newline separated values into an array.

经常使用shellcheck检查代码。它通常会给你正确的答案。在本例中,SC2207包含读取一个文件,该文件要么有空格分隔,要么将换行分隔的值放入数组中。

Don't do this

array=( $(mycommand) )

Files with values separated by newlines

mapfile -t array < <(mycommand)

Files with values separated by spaces

IFS=" " read -r -a array <<< "$(mycommand)"

The shellcheck page will give you the rationale why this is considered best practice.

shellcheck页面将告诉您为什么这被认为是最佳实践。

#6


0  

This answer says to use

这个答案是用

mapfile -t myArray < file.txt

I made a shim for mapfile if you want to use mapfile on bash < 4.x for whatever reason. It uses the existing mapfile command if you are on bash >= 4.x

如果您想在bash < 4上使用mapfile,我为mapfile做了一个shim。x不管出于什么原因。如果您在bash >= 4.x上,它将使用现有的mapfile命令

Currently, only options -d and -t work. But that should be enough for that command above. I've only tested on macOS. On macOS Sierra 10.12.6, the system bash is 3.2.57(1)-release. So the shim can come in handy. You can also just update your bash with homebrew, build bash yourself, etc.

目前,只有选项-d和-t可以工作。但这对上面的命令来说就足够了。我只在macOS上测试过。在macOS Sierra 10.12.6上,系统bash是3.2.57(1)-release。这样垫片就能派上用场了。您还可以使用homebrew更新您的bash,自己构建bash,等等。

It uses this technique to set variables up one call stack.

它使用这种技术来设置一个调用堆栈中的变量。

#1


57  

Use the mapfile command:

使用mapfile命令:

mapfile -t myArray < file.txt

The error is using for -- the idiomatic way to loop over lines of a file is:

这个错误是用于——循环文件行数的惯用方法是:

while IFS= read -r line; do echo ">>$line<<"; done < file.txt

See BashFAQ/005 for more details.

详情请参阅BashFAQ/005。

#2


4  

You can do this too:

你也可以这样做:

oldIFS="$IFS"
IFS=$'\n' arr=($(<file))
IFS="$oldIFS"
echo "${arr[1]}" # It will print `A Dog`.

Note:

注意:

Filename expansion still occurs. For example, if there's a line with a literal * it will expand to all the files in current folder. So use it only if your file is free of this kind of scenario.

文件名扩张仍然发生。例如,如果有一行文字*,它将扩展到当前文件夹中的所有文件。因此,只有在您的文件没有这种情况时才使用它。

#3


3  

mapfile and readarray (which are synonymous) are available in Bash version 4 and above. If you have an older version of Bash, you can use a loop to read the file into an array:

在Bash version 4和以上版本中,可以使用mapfile和readarray(它们是同义的)。如果您有一个旧版本的Bash,您可以使用循环将文件读入一个数组:

arr=()
while IFS= read -r line; do
  arr+=("$line")
done < file

In case the file has an incomplete (missing newline) last line, you could use this alternative:

如果文件的最后一行不完整(缺少换行符),您可以使用以下方法:

arr=()
while IFS= read -r line || [[ "$line" ]]  do
  arr+=("$line")
done < file

Related:

相关:

#4


2  

You can simply read each line from the file and assign it to an array.

您可以简单地从文件中读取每一行并将其分配给一个数组。

#!/bin/bash
i=0
while read line 
do
        arr[$i]="$line"
        i=$((i+1))
done < file.txt

#5


0  

Use mapfile or read -a

Always check your code using shellcheck. It will often give you the correct answer. In this case SC2207 covers reading a file that either has space separated or newline separated values into an array.

经常使用shellcheck检查代码。它通常会给你正确的答案。在本例中,SC2207包含读取一个文件,该文件要么有空格分隔,要么将换行分隔的值放入数组中。

Don't do this

array=( $(mycommand) )

Files with values separated by newlines

mapfile -t array < <(mycommand)

Files with values separated by spaces

IFS=" " read -r -a array <<< "$(mycommand)"

The shellcheck page will give you the rationale why this is considered best practice.

shellcheck页面将告诉您为什么这被认为是最佳实践。

#6


0  

This answer says to use

这个答案是用

mapfile -t myArray < file.txt

I made a shim for mapfile if you want to use mapfile on bash < 4.x for whatever reason. It uses the existing mapfile command if you are on bash >= 4.x

如果您想在bash < 4上使用mapfile,我为mapfile做了一个shim。x不管出于什么原因。如果您在bash >= 4.x上,它将使用现有的mapfile命令

Currently, only options -d and -t work. But that should be enough for that command above. I've only tested on macOS. On macOS Sierra 10.12.6, the system bash is 3.2.57(1)-release. So the shim can come in handy. You can also just update your bash with homebrew, build bash yourself, etc.

目前,只有选项-d和-t可以工作。但这对上面的命令来说就足够了。我只在macOS上测试过。在macOS Sierra 10.12.6上,系统bash是3.2.57(1)-release。这样垫片就能派上用场了。您还可以使用homebrew更新您的bash,自己构建bash,等等。

It uses this technique to set variables up one call stack.

它使用这种技术来设置一个调用堆栈中的变量。