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
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
ougrep -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) parareadarray
integrado. - Meu mal-didn ' não vi isso. Obrigado @St é phaneChazelas!
grep -P -o "(?<=$NOME\t).+"