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

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

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

Itere 5 vezes o loop;
obter uma linha de um arquivo (a cada iteração preciso que a próxima linha seja buscada);
use a linha como título de um arquivo;
coloque um carimbo de data/hora no início;
use a linha como argumento para ping; imprima algumas frases informando ao usuário sobre o andamento do código;

A iteração já funciona.
Se eu pular a parte sed, tudo funciona, mas executo o ping 5 vezes no mesmo alvo.
Cada linha do arquivo hosts.txt possui um único endereço IP no qual pretendo executar ping.

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  

Acredito que o problema é que estou fazendo algo errado com 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 logo antes de p bash interpretar ip como uma variável em vez da variável i mais o argumento p depois dela.

Como posso corrigir esse comportamento e não bagunçar tudo de novo?

Responder1

Presumo que você esteja usando o bash, então isso deve funcionar 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 enfrentando é bashque a maioria dos intérpretes de shell externos kshcoloca todos os componentes do pipeline em um subshell para que a outputvariável seja perdida imediatamente após ser definida.

Observe também que corrigi seu forloop que, conforme escrito, tinha um comportamento indefinido porque a ivariável não foi inicializada.

Responder2

O problema é que, como você observou, ambos ie ipsão nomes de variáveis ​​válidos. Portanto, se você quiser usar o valor $iimediatamente seguido pelo caractere p, você pode 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

Responder3

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.txtno final da última linha, após o done. Isso abre hosts.txtuma vez e apenas lê as primeiras cinco linhas dele. Conforme mencionado por don_crissti, fazer sed … hosts.txt | read output no loop significa que você está lendo o hosts.txtarquivo cinco vezes. Como read outputé paralelo ao restante do loop (não em um pipeline), o restante do código no loop terá acesso ao valor outputlido do arquivo. Além disso (como também apontou), você não precisa de touch; irá criarcommand>>filefilese ainda não existir.

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

Tenha cuidado ao passar dados desconhecidos diretamente para arquivos printf. No caso (improvável?) de um de seus “nomes de host” conter um %, seu código irá distorcer esse nome. É melhor passar dados estrangeiros para %s(para imprimir uma string).

Você não diz se deseja ler apenas as primeiras cinco linhas do hosts.txtarquivo e depois parar, ou se deseja ler o arquivo inteiro, e acontece que você sabe que ele tem cinco linhas. Se você quiser ler o arquivo inteiro, basta fazer

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 read outputinstrução falhará e o loop será encerrado.

informação relacionada