bash + usando printf per stampare in un formato speciale


12

Ho appena scritto il seguente script bash per verificare l'accesso ping nell'elenco delle macchine Linux:

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

Questo stampa:

 (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

Come posso usare printf(o qualsiasi altro comando) nel mio script bash per stampare il seguente formato?

 (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

Puoi fare un calcolo $TOTAL (length) - $MASHINE (length)per ottenere il numero di punti. Quindi utilizzare printf '.%.s' {1..$DOTS}in ogni iterazione del ciclo. Qualcosa del genere penso che funzionerà.
coffeMug

puoi per favore descrivere la tua soluzione come risposta
yael

Hai già una risposta. ;-)
coffeMug

Risposte:


19

Utilizzo dell'espansione dei parametri per sostituire gli spazi risultanti %-sdai punti:

#!/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

WOW, fammi controllare e aggiornerò presto ..........................
yael

1
Heh, intelligente! Un paio di punti pedanti: i) %2dsta aggiungendo uno spazio inutile tra parentesi (anche se potrebbe essere utile quando $ list> = 10); ii) per ottenere l' output esatto del PO , potresti voler aggiungere machine_indented=${machine_indented/../ .}per aggiungere uno spazio extra prima del primo .. Come ho detto, pedante.
terdon

ciao Choroba, puoi per favore prendere in considerazione le osservazioni di Terdon nella tua risposta?
Ya

@yael: Ora dovrebbe essere facile per te modificare la soluzione :-)
choroba,

A proposito: perché aggiungere e prima> / dev / null?
yael,

8

for m in $listè zshsintassi. In bashesso sarebbe for i in "${list[@]}".

bashnon ha operatori di imbottitura. Puoi fare il padding con printfma solo con spazi, non con caratteri arbitrari. zshha operatori di imbottitura.

#! /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

L' imbottitura operatore ${(r:25:)parameter}a destra -pad con lunghezza 25 con spazi o ${(r:25::string:)parameter}di destra -pad con qualsiasi stringa invece di spazio.

Usiamo anche printf '%4s'a sinistra -pad il (x)con spazi. ${(l:4:):-"($((++c)))"}Invece avremmo potuto usare . Una differenza notevole però è che se la stringa è lunga più di 4 caratteri, la ${(l)}troncerebbe, mentre traboccerebbe printf.


6

L' %sidentificatore di formato può richiedere una precisione ( %.20sad esempio) e proprio come quando si desidera generare un valore float su una determinata precisione ( %.4fad esempio), l'output sarà al massimo di tanti caratteri dall'argomento stringa specificato.

Quindi crea una stringa che contenga il nome della macchina e abbastanza punti per rimanere senza punti:

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

Produzione:

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

2

Con cose rubate dalla risposta di @ 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

Lo farei con fpinge awk. Sfortunatamente, awknon è printfpossibile eseguire il pad con i punti, solo con spazi o zero, quindi devo scrivere una funzione:

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

Sto usando numeri a 2 cifre con spaziatura zero tra parentesi in modo che il formato non venga rovinato se ci sono 10-99 host $list(100+ lo rovineranno comunque). L'alternativa sarebbe di ritardare la stampa fino a quando un END {}blocco, e per i / regexp-partite / a basta inserire il nome host in una di tre array, per esempio ok, fail, unknown. o solo un array associativo (ad es hosts[hostname]="OK".). Quindi puoi contare il numero di linee e usarlo per decidere quanto deve essere ampio il campo del contatore di linee.

Ho anche deciso di distinguere l'output tra host sconosciuti ( CONNECTION IMPOSSIBLE) e host non raggiungibili ( CONNECTION FAIL).

Il sort -k3é opzionale, solo gruppi l'uscita dal fpingrisultato ( "hostname è vivo", "hostname non è raggiungibile" o "nome host: Nome o servizio non conosciuto"). Senza il sort, gli host sconosciuti appariranno sempre per primi nell'output. Semplicemente sortsenza l' -k3ordinamento per nome host.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.