Separando nomes de variáveis de strings de saída sem espaços em branco

1

Eu tenho o seguinte trecho de código onde pretendo:

Iterar 5 vezes o loop;
obter uma linha de um arquivo (cada iteração eu preciso da próxima linha buscada); use a linha como um título para um arquivo; colocar um timestamp no começo dele; use a linha como argumento para ping; imprimir algumas frases informando o usuário sobre o andamento do código;

A iteração já funciona.
Se eu pular a parte sed, tudo funciona, mas eu corro o ping 5 vezes contra o mesmo alvo. Cada linha do arquivo hosts.txt tem um único endereço IP que pretendo pingar.

for ((i>=1;i<=5;i++))  
do  
sed -n "$i p" hosts.txt | read output  
    touch "$output.txt"  
    date >> "$output.txt"  
    printf "\nComeçando o teste de $output."  
    printf "\nTeste em andamento."  
    ping -c 10 -i 1 "$output" >> "$output.txt"  
done  

Eu acredito que o problema é que estou fazendo algo errado sobre a sintaxe do sed. Se eu tentar bash diretamente sed -n 1p hosts , recebo a primeira linha. Mas como eu preciso que esse número seja $ i, se eu colocar $ i antes de p bash interpreta ip como uma variável ao invés da variável i mais argumento p depois dele.

Como posso corrigir esse comportamento e não estragar essa coisa de novo?

    
por Rafael Umbelino 22.05.2016 / 22:43

3 respostas

3

Estou assumindo que você está usando o bash para que isso funcione melhor:

for ((i=1;i<=5;i++))  
do  
    sed -n "$i p" hosts.txt | (
        read output  
        touch "$output.txt"  
        date >> "$output.txt"  
        printf "\nComeçando o teste de $output."  
        printf "\nTeste em andamento."  
        ping -c 10 -i 1 "$output" >> "$output.txt"  
    )
done 

O problema que você estava sofrendo era bash , como a maioria dos intérpretes de shell fora de ksh colocam todos os componentes do pipeline em uma subshell, então a variável output é imediatamente perdida após ser definida.

Note também que eu corrigi o seu loop for que, como escrito, tinha um comportamento indefinido porque a variável i não foi inicializada.

    
por 22.05.2016 / 22:52
2

O problema é que, como você observa, ambos i e ip são nomes de variáveis válidos. Portanto, se você quiser usar o valor $i imediatamente seguido pelo caractere p , poderá usar chaves flexíveis para delimitar claramente onde o nome da variável começa e termina:

sed -n "${i}p" hosts.txt | read output
    
por 22.05.2016 / 23:09
1

Uma solução um pouco mais simples é

for ((i=1; i<=5; i++))
do
    read output
    date >> "$output.txt"
    printf "\nComeçando o teste de %s." "$output"
    printf "\nTeste em andamento."
    ping -c 10 -i 1 "$output" >> "$output.txt"
done < hosts.txt

Observe o < hosts.txt no final da última linha, após o done . Isso abre hosts.txt uma vez e apenas lê as primeiras cinco linhas dele. Como mencionado por don_crissti, fazendo sed … hosts.txt | read output no loop significa que você está lendo o arquivo hosts.txt cinco vezes. Como o read output é paralelo ao restante do loop (não em um pipeline), o resto do código no loop terá acesso ao valor de output lido do arquivo. Além disso, como também não destacou, você não precisa de touch ; %código% criará command>>file se ainda não existir.

Observe que, se um dos seus arquivos file já existe, este código irá anexar as novas informações a ele. Se você quiser descartar dados antigos e começar do zero, do hostname.txt em vez de date > "$output.txt" .

Tenha cuidado ao transmitir dados desconhecidos diretamente para date >> "$output.txt" . No caso (improvável?) De um dos seus "hostnames" ter um printf , seu código irá adulterar esse nome. É melhor transmitir dados estrangeiros para % (para imprimir uma string).

Você não diz se deseja ler apenas as cinco primeiras linhas do arquivo %s e depois parar, ou se você quiser ler o arquivo inteiro, e você sabe que são cinco linhas de comprimento. Se você quiser ler o arquivo inteiro, apenas faça

while read output
do
    date >> "$output.txt"
    printf "\nComeçando o teste de %s." "$output"
    printf "\nTeste em andamento."
    ping -c 10 -i 1 "$output" >> "$output.txt"
done < hosts.txt

Quando você chegar ao final do arquivo, a instrução hosts.txt falhará e o loop será finalizado.

    
por 23.05.2016 / 09:37