web-dev-qa-db-ja.com

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

次の形式で出力するために、bashスクリプトでprintf(またはその他のコマンド)をどのように使用できますか?

 (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
12
yael

パラメータ拡張を使用して、%-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
19
choroba

_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
_

padding演算子は${(r:25:)parameter} to right-pad with length 25 with spaceまたは${(r:25::string:)parameter} to right =-スペースの代わりに任意の文字列を埋め込む。

また、_printf '%4s'_を使用してleft -_(x)_にスペースを入れます。代わりに${(l:4:):-"($((++c)))"}を使用することもできます。ただし、大きな違いは、文字列が4文字を超える場合、${(l)}は文字列を切り捨て、printfでオーバーフローすることです。

8

%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
6
Kusalananda

私はfpingawkでそれを行います。残念ながら、awkprintfはドットで埋めることはできず、スペースまたはゼロでのみ埋め込むことができるため、関数を作成する必要があります。

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

かっこ内にゼロを埋め込んだ2桁の数字を使用しているので、$listに10〜99のホストがある場合にフォーマットが台無しになりません(100以上では台無しになります)。別の方法としては、END {}ブロックまで印刷を遅らせ、/ regexp-matches /でホスト名を3つの配列のいずれかに挿入するだけです。 okfailunknown。または1つの連想配列(例:hosts[hostname]="OK")。次に、行数をカウントし、それを使用して、行カウンターフィールドの幅を決定します。

また、出力で不明なホスト(CONNECTION IMPOSSIBLE)と到達できないホスト(CONNECTION FAIL)を区別することにしました。

sort -k3はオプションであり、fpingの結果( "hostname is alive"、 "hostname is unreachable"または "hostname:Name or service notknown")によって出力をグループ化するだけです。 sortがない場合、不明なホストは常に出力の最初に表示されます。 -k3のない単純なsortは、ホスト名でソートされます。

2
cas

@chorobaの答えから盗まれたもので:

#!/bin/bash 
list=(linux643 linux72 google.com linux862 linux12 linux88 unix_machinetru64) 
C=1 
readonly TOTAL=50 
for M in "${list[@]}" 
do 
    DOTS=$(( TOTAL - ${#M} ))
    ping -q -c 1  "$M" &>/dev/null 

    if (($?)) ;  then 
        printf "(%d) %s" "$C" "$M" ; printf "%0.s." $(seq 1 $DOTS) ; printf " CONNECTION FAILED\n" 
    else 
        printf "(%d) %s" "$C" "$M" ; printf "%0.s." $(seq 1 $DOTS) ; printf " CONNECTION OK\n"  
    fi 
    ((C=C+1)) 
done 
2
coffeMug