No Bash, como ler um arquivo e tomar cada linha como variável incremental?

1

Eu tenho um arquivo como abaixo: (list.txt)

127.0.0.1 us
127.0.0.2 uk
127.0.0.3 cn
127.0.0.4 fr
127.0.0.5 ru
127.0.0.6 bd
127.0.0.7 hk

Eu queria criar um script que mostrasse o usuário como itens a serem escolhidos.

bash ping.sh
Which ip you want to test?

1) 127.0.0.1-us
2) 127.0.0.2-uk
3) 127.0.0.3-cn
4) 127.0.0.4-fr
5) 127.0.0.5-ru
6) 127.0.0.6-bd
7) 127.0.0.7-hk

Input: 6

ping -c 5 127.0.0.6

Essa lista será alterada sempre que o arquivo for alterado. Como posso fazer isso?

    
por Fahad Ahammed 26.03.2016 / 06:07

4 respostas

3
#!/bin/bash

PS3="Input: "

while read -r addr tld; do
  addrlist+=( "$addr" ) 
done < list.txt

echo "Which ip you want to test?"

select addr in "${addrlist[@]}"; do
  ping -c5 "$addr"
  break;
done

Observe que, se seu arquivo tivesse apenas um único campo (endereço), você poderia usar o bash mapfile interno (ou seu sinônimo readarray )

mapfile -t addrlist < list.txt

para preencher o array sem looping explícito. Se você quiser a lista hifenizada exata mostrada na pergunta original, você pode fazer algo como

mapfile -t addrlist < list.txt

echo "Which ip you want to test?"

select addr in "${addrlist[@]// /-}"; do
  ping -c5 "${addr%%-*}"
  break;
done

mas o código começa a ficar feio IMHO.

    
por steeldriver 26.03.2016 / 08:43
2
#!/bin/bash

IFS=$'\n'
select choice in $(cat list.txt; echo exit)
do
    # echo "$REPLY : $choice"
    if [[ $choice != "exit" ]]
    then
        echo "your choice was: "$choice
        # Run your program here
    else
        exit
    fi
done
    
por the_velour_fog 26.03.2016 / 06:55
1

Assumindo que bash significou o comando cli (terminal) para executar o trabalho. Apenas a seção comunicacional é feita por python o comando em si é (é claro) feito por ping

Tudo em um, em um pequeno script python :

#!/usr/bin/env python3
import subprocess
import sys

print("Which ip do you want to test?\n")
# create a numbered list of the lines
ips = list(enumerate(open(sys.argv[1]).read().splitlines()))
[print(str(i+1)+") "+ip) for i, ip in ips]
# run the command to ping
subprocess.call(["ping", "-c", "5", ips[int(input("\ninput: "))-1][1]])
  • Copie o script em um arquivo vazio, salve-o como ping_ip.py
  • Execute-o com seu argumento list.txt as:

    python3 /path/to/ping_ip.py /path/to/list.txt'
    

Nota

O argumento "5" (número de pings) está na linha:

subprocess.call(["ping", "-c", "5", ips[int(input("\ninput: "))-1][1]])

mas pode muito bem ser alterado para ser usado como um argumento enquanto executa o script . Se isso for útil, por favor mencione.

    
por Jacob Vlijm 26.03.2016 / 07:46
0

Aqui está o que eu inventei em cerca de 5 a 10 minutos jogando com o AWK.

$ select entry in $(awk '{printf "%s-%s ",,}'  ips.txt) ; do                                      
> ip_address=$(awk -F '-' '{print }' <<< "$entry" )                                                                 
> echo "You selected "  "$ip_address"
> done
1) 127.0.0.1-us
2) 127.0.0.2-uk
3) 127.0.0.3-cn
4) 127.0.0.4-fr
5) 127.0.0.5-ru
6) 127.0.0.6-bd
7) 127.0.0.7-hk
#? 2
You selected  127.0.0.2

A parte complicada da sua pergunta é apenas processar as linhas do arquivo de texto que podem ser usadas apropriadamente pela estrutura select , porque você tem duas entradas por linha ali. Bem, por que não transformá-los em um item e apenas postar o processo para extrair o endereço IP? Isso é exatamente o que estou fazendo no código acima.

Note que a primeira substituição de parâmetro é deixada sem aspas propositadamente - nós queremos que o primeiro comando se expanda para cada item separado, separado por espaços, nós não queremos que ele seja tratado como uma string.

O que é bom nessa abordagem é que ela é imune ao local ausente, por exemplo, se na escolha # 2 uk estiver faltando, ainda poderemos ler 127.0.0.2

    
por Sergiy Kolodyazhnyy 28.03.2016 / 08:37