BASH lendo arquivo txt e armazenando na matriz

Estou escrevendo meu primeiro script BASH, tenho alguma experiência com c e c #, então acho que a lógica do programa está correto .. é apenas a sintaxe é tão complicada porque aparentemente existem bilhões de maneiras de escrever a mesma coisa!

De qualquer forma, aqui está o script: ele simplesmente verifica se o argumento (string) é contido em um determinado arquivo. Nesse caso, ele armazena cada linha do arquivo em um array e grava um item do array em um arquivo. Tenho certeza de que deve haver maneiras mais fáceis de conseguir isso, mas quero praticar com loops bash

 #!/bin/bash NOME=$1 c=0 #IF NAME IS FOUND IN THE PHONEBOOK THANK 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 

Este código retorna apenas o segundo item de myArray (myArray[2] ou a segunda linha do arquivo) .. por quê?

Comentários

  • Que relevância tem o \ t? Tanto o texto quanto o resto do código se referem apenas às linhas.
  • Não é uma resposta direta, então ' é apenas uma comentário, mas eu ' d faria isso com um por um liner grep; grep -P -o "(?<=$NOME\t).+"
  • @Patrick Classic Problema XY , então acho que seu comentário deve ser uma resposta. Afinal, ele faz a coisa certa.

Resposta

IFS=$"\n" a=($(cat phonebook.txt)) for i in $(seq ${#a[*]}); do [[ ${a[$i-1]} = $name ]] && echo "${a[$i]}" done 

No Bash 4, IFS=$"\n" a=($(cat phonebook.txt)) pode ser substituído por mapfile -t a < phonebook.txt.

grep -A1 imprime uma linha após a correspondência. -x desativa regex como -F, mas corresponde apenas a l completo ines.

grep -x "$name" -A1 phonebook.txt | tail -n1 

Comentários

  • Você pode querer validar o conteúdo do arquivo primeiro. Depende de você.
  • -x não desativa regex .
  • Deixando isso $(cat phonebook.txt) sem aspas nesse contexto de lista invoca split + glob na expansão. Aqui, você deseja a parte dividir , mas não a parte glob , por isso deve ser desativada (set -o noglob).
  • Deve ser grep -xFe "$name" -A1 phonebook.txt ou grep -xFA1 -- "$name" phonebook.txt ou ' não funcionará corretamente se $name começar com - ou $POSIXLY_CORRECT estiver no ambiente.
  • Em bash, é ' s [[ $string = $pattern ]] ou [[ $string = "$otherstring" ]]. Ou IOW, você precisa citar expansões de palavras no lado direito do = operador dentro de [[...]] se você não ' não quero que seja considerado um padrão.

Resposta

index=0 while read line; do myArray[index]="$line" done < inputfile 

As versões mais recentes do bash suportam matrizes associativas. Isso tornaria mais fácil:

declare -A myArray while read name; do read number myArray[name]="$number" done < inputfile echo ${myArray[name]} 

Comentários

  • e como você retornaria o item de myArray [nome + 1]?
  • No exemplo indexado você já tinha a solução, portanto, não ' copiei.
  • Posso estar errado, mas usar esse tubo não tornaria meuArray " invisível " para fora do loop ???
  • @FredericYesidPe ñ aS á nchez Nem a pergunta nem minha resposta contém um pipeline, portanto, eu não ' não sei do que você está falando.
  • " enquanto lê o nome; " me parece um pipeline, de qualquer forma, encontrei o " declare -a array " que corrige problemas que tive antes, obrigado !!! +1

Resposta

Em uma pergunta intitulada “ BASH lendo arquivo txt e armazenando em array “Acho que readarray merece uma menção. Um exemplo deste método que uso para ler arquivos de teste em uma matriz seria:

readarray -t arrayIPblacklist < /etc/postfix/IP-black-list.txt 

O anterior carrega um arquivo de endereços IP separados por novas linhas em uma matriz chamada “ arrayIPblacklist “. Funcionaria em seu arquivo de lista telefônica. readarray foi introduzido no bash 4, portanto, esse método não funcionará em hosts mais antigos que executam versões anteriores do bash.

O -t remove os delimitadores de nova linha de cada elemento, já que na maioria das vezes você não quer que eles sejam incluídos.

$ seq 3 | bash -c "readarray a; printf "<%q>\n" "${a[@]}"" <$"1\n"> <$"2\n"> <$"3\n"> $ seq 3 | bash -c "readarray -t a; printf "<%q>\n" "${a[@]}"" <1> <2> <3> 

Comentários

  • Observe que a resposta aceita já mencionou mapfile que é outro nome (embora mais confuso) para readarray integrado.
  • Meu mal-didn ' não vi isso. Obrigado @St é phaneChazelas!

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *