変数名を空白なしで出力文字列から分離する

変数名を空白なしで出力文字列から分離する

次のようなコード スニペットがあります。

ループを 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

問題は、お気づきのとおり、 と はどちらも有効な変数名であるということですiipしたがって、値の$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.txt1 回だけ開いて、そこから最初の 5 行だけを読み取ります。don_crissti が述べたように、ループ内で を実行すると、ファイルを 5 回sed … hosts.txt | read output 読み取ることになります。 はループの残りの部分と並列であるため (パイプラインではない)、ループ内の残りのコードはファイルから読み取った の値にアクセスできます。また (don も指摘したように)、 は必要ありません。 ; は作成します。hosts.txtread outputoutputtouchcommand>>filefileまだ存在しない場合は。

ファイルの 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は失敗し、ループは終了します。

関連情報