Отделение имен переменных от выходных строк без пробелов

Отделение имен переменных от выходных строк без пробелов

У меня есть следующий фрагмент кода, в котором я собираюсь:

Выполнить цикл 5 раз;
получить строку из файла (на каждой итерации мне нужно извлечь следующую строку);
использовать строку в качестве заголовка файла;
поместить временную метку в его начало;
использовать строку в качестве аргумента для ping; вывести несколько предложений, информирующих пользователя о ходе выполнения кода;

Итерация уже работает.
Если я пропускаю часть sed, все работает, но я запускаю ping 5 раз против одной и той же цели.
Каждая строка файла hosts.txt имеет один IP-адрес, который я собираюсь пинговать.

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  

Я думаю, проблема в том, что я делаю что-то неправильно с синтаксисом sed. Если я попробую напрямую в bash sed -n 1p hosts, я получу первую строку. Но так как мне нужно, чтобы это число было $i, если я поставлю $i прямо перед p, bash интерпретирует ip как переменную, а не как переменную i плюс аргумент p после нее.

Как мне исправить это поведение и не испортить все снова?

решение1

Я предполагаю, что вы используете bash, поэтому это должно работать лучше:

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 

Проблема, с которой вы столкнулись, заключается в том bash, что большинство внешних интерпретаторов оболочки kshпомещают все компоненты конвейера в подоболочку, поэтому outputпеременная сразу теряется после установки.

Обратите внимание, что я исправил ваш forцикл, который в том виде, в котором он был написан, имел неопределенное поведение, поскольку iпеременная не была инициализирована.

решение2

Проблема в том, что, как вы заметили, и iи ipявляются допустимыми именами переменных. Так что если вы хотите использовать значение, $iза которым сразу следует символ p, вы можете использовать изогнутые фигурные скобки, чтобы четко разграничить начало и конец имени переменной:

sed -n "${i}p" hosts.txt | read output

решение3

Немного более простое решение:

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

Обратите внимание < hosts.txtна в конце последней строки, после done. Это открывается hosts.txtодин раз и просто считывает первые пять строк из него. Как упомянул don_crissti, выполнение sed … hosts.txt | read output в цикле означает, что вы читаете hosts.txtфайл пять раз. Поскольку выполняется read outputпараллельно с остальной частью цикла (не в конвейере), остальная часть кода в цикле будет иметь доступ к значению outputread из файла. Также (как также указал don), вам не нужно touch; создастcommand>>filefileесли его еще не существует.

Обратите внимание, что если один из ваших hostname.txtфайлов уже существует, этот код добавит к нему новую информацию. Если вы хотите удалить старые данные и начать с нуля, сделайте date > "$output.txt"вместо date >> "$output.txt".

Будьте осторожны, передавая неизвестные данные напрямую в printf. В (маловероятном?) случае, если одно из ваших «имен хостов» содержит %в себе , ваш код исказит это имя. Лучше передавать чужие данные в %s(чтобы вывести строку).

Вы не говорите, хотите ли вы прочитать только первые пять строк файла hosts.txtи затем остановиться, или вы хотите прочитать весь файл, и вы случайно знаете, что он состоит из пяти строк. Если вы хотите прочитать весь файл, просто сделайте

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

Когда вы дойдете до конца файла, оператор read outputзавершится ошибкой, и цикл прервется.

Связанный контент