次のようなコード スニペットがあります。
ループを 5 回繰り返し、
ファイルから 1 行を取得し (各繰り返しで次の行を取得する必要があります)、
その行をファイルのタイトルとして使用し、
その先頭にタイムスタンプを配置し、
その行を ping の引数として使用し、コードの進行状況をユーザーに通知するいくつかの文章を出力します。
反復処理はすでに機能しています。sed
部分をスキップすると、すべてが機能しますが、同じターゲットに対して ping を 5 回実行します。
ファイル hosts.txt の各行には、ping を実行する IP アドレスが 1 つずつあります。
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 である必要があるため、p の直前に $i を置くと、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
1 回だけ開いて、そこから最初の 5 行だけを読み取ります。don_crissti が述べたように、ループ内で を実行すると、ファイルを 5 回sed … hosts.txt | read output
読み取ることになります。 はループの残りの部分と並列であるため (パイプラインではない)、ループ内の残りのコードはファイルから読み取った の値にアクセスできます。また (don も指摘したように)、 は必要ありません。 ; は作成します。hosts.txt
read output
output
touch
command >> file
file
まだ存在しない場合は。
ファイルの 1 つがすでに存在する場合hostname.txt
、このコードは新しい情報をそのファイルに追加します。古いデータを破棄して最初からやり直す場合は、date > "$output.txt"
の代わりにを実行しますdate >> "$output.txt"
。
不明なデータを に直接渡すことには注意してくださいprintf
。(あり得ないかもしれませんが)「ホスト名」の 1 つに が含まれている場合、コードによってその名前が文字化けします。外部データを に渡す(文字列を出力する)%
方が適切です。%s
ファイルの最初の5行だけを読み込んhosts.txt
で停止するのか、それともファイル全体を読み取り、たまたま5行の長さだとわかっているのかは指定しません。ファイル全体を読み取りたい場合は、次のようにします。
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
は失敗し、ループは終了します。