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

时间:2013-04-02 20:14:29

标签: linux bash loops if-statement

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

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

#!/bin/bash

NOME=$1
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

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

2 个答案:

答案 0 :(得分:2)

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

  • 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
    

    两者非常相似,但条件表达式的语法更清晰(例如在测试命令中,>重定向输出,而\>是字符串比较;在[[ ]] a普通>是一个比较)。

    在任何一种情况下,您都需要为myArray使用适当的$表达式,否则它将被解释为文字。另一方面,在“$ {myArray [i]}”中的$之前需要i,因为它位于数值表达式上下文中,因此将自动扩展。

    最后,请注意元素之间的空格是绝对必需的 - 在shell中,空格是非常重要的分隔符,而不仅仅是因为它们通常在c中可读。

答案 1 :(得分:2)

1.-这是你用小调整写的

#!/bin/bash

NOME=$1

#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.-但您也可以读取数组并停止循环:

#!/bin/bash

NOME=$1

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.-以下改进了一些事情。假设a)$ NAME匹配包含它的整行,b)在找到$ NOME之后总是有一行,这将起作用;如果没有(如果$ NOME可以是电话簿中的最后一行),那么你需要进行小的调整。

!/bin/bash
PHONEBOOK="/root/phonebook.txt"
NUMBERTOCALL="/root/numbertocall.txt"
NOME="$1"
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