从 Bash 中的文本文件创建数组
Creating an array from a text file in Bash
一个脚本接受一个 URL,解析它以获得所需的字段,并将其输出重定向以保存在文件 file.txt 中。每次找到一个字段时,输出都会保存在一个新行中。
file.txt
A Cat
A Dog
A Mouse
etc...
我想使用 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
当我 运行 这个脚本时,空格导致单词被拆分而不是
期望的输出
Element [0]: A Cat
Element [1]: A Dog
etc...
我最终得到这个:
实际产量
Element [0]: A
Element [1]: Cat
Element [2]: A
Element [3]: Dog
etc...
如何调整下面的循环,使每一行的整个字符串与数组中的每个变量一一对应?
使用mapfile
命令:
mapfile -t myArray < file.txt
错误是使用 for
-- 遍历文件的 行 的惯用方法是:
while IFS= read -r line; do echo ">>$line<<"; done < file.txt
有关详细信息,请参阅 BashFAQ/005。
你也可以这样做:
oldIFS="$IFS"
IFS=$'\n' arr=($(<file))
IFS="$oldIFS"
echo "${arr[1]}" # It will print `A Dog`.
注:
文件名扩展仍然存在。例如,如果有一行文字为 *
,它将扩展到当前文件夹中的所有文件。所以只有当你的文件没有这种情况时才使用它。
您可以简单地从文件中读取每一行并将其分配给一个数组。
#!/bin/bash
i=0
while read line
do
arr[$i]="$line"
i=$((i+1))
done < file.txt
mapfile
和 readarray
(它们是同义词)在 Bash 版本 4 及更高版本中可用。如果你有旧版本的Bash,你可以使用循环将文件读入数组:
arr=()
while IFS= read -r line; do
arr+=("$line")
done < file
如果文件的最后一行不完整(缺少换行符),您可以使用此替代方法:
arr=()
while IFS= read -r line || [[ "$line" ]]; do
arr+=("$line")
done < file
相关:
使用mapfile或读取-a
始终使用 shellcheck. It will often give you the correct answer. In this case SC2207 检查您的代码,包括将 space 分隔值或换行符分隔值读取到数组中的文件。
不要这样做
array=( $(mycommand) )
值由换行符分隔的文件
mapfile -t array < <(mycommand)
值由 spaces
分隔的文件
IFS=" " read -r -a array <<< "$(mycommand)"
shellcheck 页面会告诉您为什么这是最佳实践。
表示使用
mapfile -t myArray < file.txt
如果您想在 bash < 4.x 上使用 mapfile
,我为 mapfile
创建了一个 shim。如果您使用 bash >= 4.x
,它会使用现有的 mapfile
命令
目前,只有选项 -d
和 -t
有效。但这对于上面的命令应该足够了。我只在 macOS 上测试过。在 macOS Sierra 10.12.6 上,系统 bash 是 3.2.57(1)-release
。所以垫片可以派上用场。您也可以只用自制软件更新 bash,自己构建 bash,等等
它使用this technique设置一个调用堆栈的变量。
一个脚本接受一个 URL,解析它以获得所需的字段,并将其输出重定向以保存在文件 file.txt 中。每次找到一个字段时,输出都会保存在一个新行中。
file.txt
A Cat
A Dog
A Mouse
etc...
我想使用 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
当我 运行 这个脚本时,空格导致单词被拆分而不是
期望的输出
Element [0]: A Cat
Element [1]: A Dog
etc...
我最终得到这个:
实际产量
Element [0]: A
Element [1]: Cat
Element [2]: A
Element [3]: Dog
etc...
如何调整下面的循环,使每一行的整个字符串与数组中的每个变量一一对应?
使用mapfile
命令:
mapfile -t myArray < file.txt
错误是使用 for
-- 遍历文件的 行 的惯用方法是:
while IFS= read -r line; do echo ">>$line<<"; done < file.txt
有关详细信息,请参阅 BashFAQ/005。
你也可以这样做:
oldIFS="$IFS"
IFS=$'\n' arr=($(<file))
IFS="$oldIFS"
echo "${arr[1]}" # It will print `A Dog`.
注:
文件名扩展仍然存在。例如,如果有一行文字为 *
,它将扩展到当前文件夹中的所有文件。所以只有当你的文件没有这种情况时才使用它。
您可以简单地从文件中读取每一行并将其分配给一个数组。
#!/bin/bash
i=0
while read line
do
arr[$i]="$line"
i=$((i+1))
done < file.txt
mapfile
和 readarray
(它们是同义词)在 Bash 版本 4 及更高版本中可用。如果你有旧版本的Bash,你可以使用循环将文件读入数组:
arr=()
while IFS= read -r line; do
arr+=("$line")
done < file
如果文件的最后一行不完整(缺少换行符),您可以使用此替代方法:
arr=()
while IFS= read -r line || [[ "$line" ]]; do
arr+=("$line")
done < file
相关:
使用mapfile或读取-a
始终使用 shellcheck. It will often give you the correct answer. In this case SC2207 检查您的代码,包括将 space 分隔值或换行符分隔值读取到数组中的文件。
不要这样做
array=( $(mycommand) )
值由换行符分隔的文件
mapfile -t array < <(mycommand)
值由 spaces
分隔的文件IFS=" " read -r -a array <<< "$(mycommand)"
shellcheck 页面会告诉您为什么这是最佳实践。
mapfile -t myArray < file.txt
如果您想在 bash < 4.x 上使用 mapfile
,我为 mapfile
创建了一个 shim。如果您使用 bash >= 4.x
mapfile
命令
目前,只有选项 -d
和 -t
有效。但这对于上面的命令应该足够了。我只在 macOS 上测试过。在 macOS Sierra 10.12.6 上,系统 bash 是 3.2.57(1)-release
。所以垫片可以派上用场。您也可以只用自制软件更新 bash,自己构建 bash,等等
它使用this technique设置一个调用堆栈的变量。