我有以下我想要的程式碼片段:
迭代5次循環;
從文件中取得一行(每次迭代我都需要取得下一行);
使用該行作為文件的標題;
在其開頭添加一個時間戳記;
使用該行作為 ping 的參數;列印一些句子,通知使用者代碼的進度;
迭代已經起作用了。
如果我跳過 sed 部分,一切都會正常,但我對同一目標執行 ping 5 次。
檔案hosts.txt 的每一行都有一個我打算對其進行ping 操作的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
,就像大多數外部 shell 解釋器一樣ksh
,將所有管道組件放入子 shell 中,因此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
與循環的其餘部分並行(不在管道中),因此循環中的其餘程式碼將有權存取output
從文件中讀取的值。另外(正如 don 也指出的那樣),你不需要touch
; 將創造command >> file
file
如果它尚不存在。
請注意,如果您的文件之一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
語句將失敗,循環將終止。