bash + printfを使用して特別な形式で印刷する

bash + printfを使用して特別な形式で印刷する

Linuxコンピュータのリストからpingアクセスを確認するために、次のbashスクリプトを作成しました。

for M in $list
 do
   ping -q -c 1  "$M" >/dev/null 
          if [[ $? -eq 0 ]]
   then
    echo "($C) $MACHINE CONNECTION OK"
   else
    echo "($C) $MACHINE CONNECTION FAIL"
   fi

   let C=$C+1
done

これは以下を印刷します:

 (1) linux643 CONNECTION OK
 (2) linux72 CONNECTION OK
 (3) linux862 CONNECTION OK
 (4) linux12 CONNECTION OK
 (5) linux88 CONNECTION OK
 (6) Unix_machinetru64 CONNECTION OK

printfbashスクリプトで(または他のコマンド)を使用して次の形式を印刷するにはどうすればよいですか?

 (1) linux643 ............ CONNECTION OK
 (2) linux72 ............. CONNECTION OK
 (3) linux862 ............ CONNECTION OK
 (4) linux12 ............. CONNECTION OK
 (5) linux88 ............. CONNECTION FAIL
 (6) Unix_machinetru64 ... CONNECTION OK

答え1

パラメータ拡張を使用して、ドットによる%-sスペースを置き換えます。

#!/bin/bash
list=(localhost google.com nowhere)
C=1
for M in "${list[@]}"
do
    machine_indented=$(printf '%-20s' "$M")
    machine_indented=${machine_indented// /.}

    if ping -q -c 1  "$M" &>/dev/null ;  then
        printf "(%2d) %s CONNECTION OK\n" "$C" "$machine_indented"
    else
        printf "(%2d) %s CONNECTION FAIL\n" "$C" "$machine_indented"
    fi
    ((C=C+1))
done

答え2

for m in $list文法ですzsh。まさにbashそこにfor i in "${list[@]}"

bashパディング演算子はありません。パディングにはスペースを使用できますが、printf任意の文字ではなくスペースのみを使用できます。zshパディング演算子があります。

#! /bin/zsh -
list=(
  linux643
  linux72
  linux862
  linux12
  linux88
  Unix_machinetru64
)
c=0
for machine in $list; do
  if ping -q -c 1 $machine >& /dev/null; then
    state=OK
  else
    state=FAIL
  fi
  printf '%4s %s\n' "($((++c)))" "${(r:25::.:):-$machine } CONNECTION $state"
done

これ充填材オペレーター${(r:25:)parameter}正しい- スペースがあるパッドの長さ25${(r:25::string:)parameter}または正しい- スペースの代わりに任意の文字列で埋めます。

私達はまたprintf '%4s'使用します- 空白で埋めます(x)。私たちはそれを代わりに使用することもできました${(l:4:):-"($((++c)))"}。ただし、1つの重要な違いは、文字列が4文字を超えると切り捨てられ、${(l)}オーバーフローが発生することですprintf

答え3

書式%s指定子は精度(%.20s例:)を取ることができます。浮動小数点値を特定の精度(例えば)に出力したい場合、%.4f出力は与えられた文字列引数の最大文字数です。

したがって、マシン名とポイントの両方を使用するのに十分なポイントを含む文字列を作成します。

cnt=0
for hname in vboxhost ntp.stupi.se example.com nonexistant; do
   if ping -q -c 1  "$hname" >/dev/null 2>&1; then
       status="OK"
   else
       status="FAIL"
   fi

   printf "(%d) %.20s CONNECTION %s\n" \
       "$(( ++cnt ))" "$hname ...................." "$status"

done

出力:

(1) vboxhost ........... CONNECTION OK
(2) ntp.stupi.se ....... CONNECTION OK
(3) example.com ........ CONNECTION OK
(4) nonexistant ........ CONNECTION FAIL

答え4

fping私はandにしますawk。残念ながら、awk'printfはドットで埋められず、空白またはゼロで埋めることができるので、次の関数を書く必要がありました。

list=(kali surya indra ganesh durga hanuman nonexistent)

fping "${list[@]}" 2>&1 | 
  sort -k3 |
  awk -F'[: ]' 'BEGIN { fmt="(%02d) %s CONNECTION %s\n"};

       function dotpad(s,maxlen,     l,c,pads) {
         l = maxlen - length(s);
         pads = "";
         for (c=0;c<l;c++) {pads=pads"."};
         return s " " pads
       };

       /alive$/       { printf fmt, ++i, dotpad($1,19), "OK" };
       /unreachable$/ { printf fmt, ++i, dotpad($1,19), "FAIL" }
       /not known$/   { printf fmt, ++i, dotpad($1,19), "IMPOSSIBLE" } '
(01) durga .............. CONNECTION OK
(02) ganesh ............. CONNECTION OK
(03) indra .............. CONNECTION OK
(04) kali ............... CONNECTION OK
(05) nonexistent ........ CONNECTION IMPOSSIBLE
(06) hanuman ............ CONNECTION FAIL
(07) surya .............. CONNECTION FAIL

10〜99のホストがあっても型がめちゃくちゃにならないように、括弧内にゼロで埋められた2桁の数字を使用します$list(100+はまだ台無しです)。別のアプローチは、END {}ブロックが発生するまで印刷を遅らせ、/regexp-matches/は3つの配列のうちの1つにのみホスト名を挿入することです(例えばok、、、failunknown。または、単に連想配列(たとえばhosts[hostname]="OK")です。その後、行数を計算し、それを使用して行カウンタフィールドの幅を決定できます。

また、出力で未知のホスト(CONNECTION IMPOSSIBLE)と接続できないホスト(CONNECTION FAIL)を区別することにしました。

オプションで、sort -k3結果fping(「ホスト名がアクティブです」、「ホスト名に接続できません」、または「ホスト名:名前またはサービスが不明」)に基づいて出力をグループ化するだけです。そうでない場合、sort未知のホストは常に出力の最初に表示されます。ホスト名別にソートはsortありません-k3

関連情報