在 Bash 中从文本文件创建数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30988586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:00:43  来源:igfitidea点击:

Creating an array from a text file in Bash

arraysbashloopsscriptingvariable-assignment

提问by user2856414

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

文件.txt

A Cat
A Dog
A Mouse 
etc... 

I want to take file.txtand 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:

我想file.txt在一个新脚本中从中获取并创建一个数组,其中每一行都成为数组中自己的字符串变量。到目前为止,我已经尝试过:

#!/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?

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

回答by glenn Hymanman

Use the mapfilecommand:

使用mapfile命令:

mapfile -t myArray < file.txt

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

错误正在使用for- 循环文件的惯用方法是:

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

See BashFAQ/005for more details.

有关更多详细信息,请参阅BashFAQ/005

回答by codeforester

mapfileand 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:

mapfilereadarray(它们是同义词)在 Bash 版本 4 及更高版本中可用。如果您有旧版本的 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:

有关的:

回答by Jahid

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.

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

回答by Prateek Joshi

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

回答by Cameron Lowell Palmer

Use mapfile or read -a

使用 mapfile 或 read -a

Always check your code using shellcheck. It will often give you the correct answer. In this case SC2207covers 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 页面将为您提供为什么这被认为是最佳实践的基本原理。

回答by dosentmatter

This answersays to use

这个答案说使用

mapfile -t myArray < file.txt

I made a shimfor mapfileif you want to use mapfileon bash < 4.x for whatever reason. It uses the existing mapfilecommand if you are on bash >= 4.x

我做了一个垫片mapfile,如果你想使用mapfile上的bash <4.x版无论出于何种原因。mapfile如果您使用 bash >= 4.x,它会使用现有命令

Currently, only options -dand -twork. 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. 所以垫片可以派上用场。您也可以使用自制软件更新您的 bash,自己构建 bash 等。

It uses this techniqueto set variables up one call stack.

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