bash Bash读取txt文件并存储在数组中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15773507/
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-18 05:04:47  来源:igfitidea点击:

Bash reading txt file and storing in array

linuxbashloopsif-statement

提问by Aaron Ullal

I'm writing my first Bash script, I have some experience with C and C# so I think the logic of the program is correct, it's just the syntax is so complicated because apparently there are many different ways to write the same thing!

我正在编写我的第一个 Bash 脚本,我对 C 和 C# 有一些经验,所以我认为程序的逻辑是正确的,只是语法太复杂了,因为显然有很多不同的方法可以编写相同的内容!

Here is the script, it simply checks if the argument (string) is contained in a certain file. If so it stores each line of the file in an array and writes an item of the array in a file. I'm sure there must be easier ways to achieve that but I want to do some practice with bash loops

这是脚本,它只是检查参数(字符串)是否包含在某个文件中。如果是这样,它将文件的每一行存储在一个数组中,并将该数组的一个项目写入一个文件中。我确信必须有更简单的方法来实现这一点,但我想用 bash 循环做一些练习

#!/bin/bash

NOME=
c=0

#IF NAME IS FOUND IN THE PHONEBOOK THEN STORE EACH LINE OF THE FILE INTO ARRAY
#ONCE THE ARRAY IS DONE GET THE INDEX OF MATCHING NAME AND RETURN ARRAY[INDEX+1]

if grep "$NOME" /root/phonebook.txt ; then
        echo "CREATING ARRAY"
        while read line
        do
                myArray[$c]=$line # store line
                c=$(expr $c + 1) # increase counter by 1
        done < /root/phonebook.txt

else
        echo "Name not found"
fi

c=0
for i in myArray;
        do
              if   myArray[$i]="$NOME" ;  then
                 echo ${myArray[i+1]} >> /root/numbertocall.txt
              fi

done

This code returns the only the second item of myArray(myArray[2]) or the second line of the file, why?

此代码仅返回myArray( myArray[2])的第二项或文件的第二行,为什么?

采纳答案by Gordon Davisson

The first part (where you build the array) looks ok, but the second part has a couple of serious errors:

第一部分(您构建数组的地方)看起来不错,但第二部分有几个严重的错误:

  • for i in myArray;-- this executes the loop once, with $i set to "myArray". In this case, you want $i to iterate over the indexes of myArray, so you need to use

    for i in "${!myArray[@]}"
    

    or

    for ((i=0; i<${#a[@]}; i++))
    

    (although I generally prefer the first, since it'll work with noncontiguous and associative arrays).

    Also, you don't need the ;unless dois on the same line (in shell, ;is mostly equivalent to a line break so having a semicolon at the end of a line is redundant).

  • if myArray[$i]="$NOME" ; then-- the ifstatement takes a command, and will therefore treat myArray[$i]="$NOME"as an assignment command, which is not at all what you wanted. In order to compare strings, you could use the testcommand or its synonym [

    if [ "${myArray[i]}" = "$NOME" ]; then
    

    or a bash conditional expression

    if [[ "${myArray[i]}" = "$NOME" ]]; then
    

    The two are very similar, but the conditional expression has much cleaner syntax (e.g. in a test command, >redirects output, while \>is a string comparison; in [[ ]]a plain >is a comparison).

    In either case, you need to use an appropriate $expression for myArray, or it'll be interpreted as a literal. On the other hand, you don'tneed a $before the iin "${myArray[i]}" because it's in a numeric expression context and therefore will be expanded automatically.

    Finally, note that the spaces between elements are absolutely required -- in shell, spaces are very important delimiters, not just there for readability like they usually are in c.

  • for i in myArray;-- 这将执行一次循环,将 $i 设置为“myArray”。在这种情况下,您希望 $i 遍历 myArray 的索引,因此您需要使用

    for i in "${!myArray[@]}"
    

    或者

    for ((i=0; i<${#a[@]}; i++))
    

    (虽然我通常更喜欢第一个,因为它可以处理非连续和关联数组)。

    此外,您不需要;除非do在同一行上(在 shell 中,;它主要相当于换行符,因此在行尾使用分号是多余的)。

  • if myArray[$i]="$NOME" ; then-- 该if语句接受一个命令,因此将被myArray[$i]="$NOME"视为一个赋值命令,这根本不是您想要的。为了比较字符串,您可以使用test命令或其同义词[

    if [ "${myArray[i]}" = "$NOME" ]; then
    

    或 bash 条件表达式

    if [[ "${myArray[i]}" = "$NOME" ]]; then
    

    两者非常相似,但条件表达式的语法要简洁得多(例如,在测试命令中,>重定向输出,while\>是字符串比较;在[[ ]]普通情况下>是比较)。

    无论哪种情况,您都需要$为 myArray使用适当的表达式,否则它将被解释为文字。在另一方面,你也不需要$之前i在“$ {myArray的[I]}”,因为它是在数字表达式中,因此将自动扩展。

    最后,请注意元素之间的空格是绝对需要的——在 shell 中,空格是非常重要的分隔符,而不仅仅是为了可读性,就像在 c 中通常那样。

回答by Robert Vila

1.-This is what you wrote with small adjustments

1.-这是你写的小调整

#!/bin/bash

NOME=

#IF NAME IS FOUND IN THE PHONE-BOOK **THEN** READ THE PHONE BOOK LINES INTO AN ARRAY VARIABLE
#ONCE THE ARRAY IS COMPLETED, GET THE INDEX OF MATCHING LINE AND RETURN ARRAY[INDEX+1]

c=0
if grep "$NOME" /root/phonebook.txt ; then

       echo "CREATING ARRAY...."
       IFS= while read -r line    #IFS= in case you want to preserve leading and trailing spaces
       do
             myArray[c]=$line     # put line in the array
             c=$((c+1))           # increase counter by 1
       done < /root/phonebook.txt


       for i in ${!myArray[@]}; do
             if  myArray[i]="$NOME" ;  then
                 echo ${myArray[i+1]} >> /root/numbertocall.txt
             fi
       done


else
       echo "Name not found"
fi

2.-But you can also read the array and stop looping like this:

2.-但您也可以读取数组并停止循环,如下所示:

#!/bin/bash

NOME=

c=0
if grep "$NOME" /root/phonebook.txt ; then

       echo "CREATING ARRAY...."
       readarray myArray < /root/phonebook.txt


       for i in ${!myArray[@]}; do
             if  myArray[i]="$NOME" ;  then
                 echo ${myArray[i+1]} >> /root/numbertocall.txt
                 break            # stop looping
             fi
       done


else
       echo "Name not found"
fi
exit 0

3.- The following improves things. Supposing a)$NAME matches the whole line that contains it and b)there's always one line after a $NOME found, this will work; if not (if $NOME can be the last line in the phone-book), then you need to do small adjustments.

3.- 以下改进了一些东西。假设 a)$NAME 匹配包含它的整行,并且 b) 在找到 $NOME 之后总是有一行,这将起作用;如果不是(如果 $NOME 可以是电话簿中的最后一行),那么您需要做一些小的调整。

!/bin/bash
PHONEBOOK="/root/phonebook.txt"
NUMBERTOCALL="/root/numbertocall.txt"
NOME=""
myline=""

myline=$(grep -A1 "$NOME" "$PHONEBOOK" | sed '1d')

if [ -z "$myline" ]; then 
      echo "Name not found :-("

else
      echo -n "$NOME FOUND.... "
      echo "$myline" >> "$NUMBERTOCALL"
      echo  " .... AND SAVED! :-)"

fi
exit 0