Reading an array from a file in bash - “not found”

2019-09-20 00:47发布

I have a text file with a few basic words:

-banana
-mango
-sleep

When I run my script:

#!/bin/sh
WORD_FILE="testwoord.txt"
WORDS_ARRAY=cat $WORD_FILE

The output is like:

/home/username/bin/testword.txt: 1 /home/username/bin/restword.txt: banana: not found
/home/username/bin/testword.txt: 1 /home/username/bin/restword.txt: mango: not found
/home/username/bin/testword.txt: 1 /home/username/bin/restword.txt: sleep: not found

Why is it doing this? What I actually want is a script that reads words from a .txt file and puts it in an array.

2条回答
Deceive 欺骗
2楼-- · 2019-09-20 01:04

To explain why this doesn't work:

WORDS_ARRAY=cat $WORD_FILE

runs the command generated by expanding, string-splitting, and glob-expanding $WORD_FILE with the variable WORDS_ARRAY exported in the environment with the value cat.


Instead, consider:

#!/bin/bash
#      ^^ -- important that this is bash, not sh: POSIX sh doesn't have arrays!

WORD_FILE=testword.txt
readarray -t WORDS_ARRAY <"$WORD_FILE"
printf 'Read a word: %q\n' "${WORDS_ARRAY[@]}"

...which will create an actual array, not a string variable containing whitespace (as WORDS_ARRAY=$(cat $WORD_FILE) would).


By the way, using all-upper-case variable names is bad form here. To quote the POSIX spec:

Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2008 consist solely of uppercase letters, digits, and the ( '_' ) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.

查看更多
成全新的幸福
3楼-- · 2019-09-20 01:09

To complement Charles Duffy's helpful answer:

Note that the variable names were changed to lowercase, as per Charles' recommendation.

Here a bash 3.x (and above) version of the command for reading lines into a bash array (readarray requires bash 4.x):

IFS=$'\n' read -d '' -ra words_array < "$word_file"

If you want to store individual words (across lines), use:

read -d '' -ra words_array < "$word_file"

To print the resulting array:

for ((i=0; i<"${#words_array[@]}"; i++)); do echo "word #$i: "${words_array[i]}""; done
查看更多
登录 后发表回答