bash + за допомогою printf для друку у спеціальному форматі


12

Я щойно написав наступний сценарій bash, щоб перевірити доступ до ping у списку машин 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

Це відбитки:

 (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

Як я можу використовувати printf(або будь-яку іншу команду) в моєму скрипті bash для друку наступного формату?

 (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

Ви можете зробити розрахунок, $TOTAL (length) - $MASHINE (length)щоб отримати кількість крапок. Потім використовуйте printf '.%.s' {1..$DOTS}в кожному циклі ітерацію. Щось подібне, я думаю, спрацює.
coffeMug

чи можете ви описати своє рішення як відповідь
yael

Ви вже маєте відповідь. ;-)
coffeMug

Відповіді:


19

Використання розширення параметрів для заміни пробілів в результаті %-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

WOW, дозвольте перевірити, і я скоро
оновлю

1
Хе, розумний! Кілька педантичних моментів: i) %2dдодавання непотрібного місця у дужки (хоча це може бути корисно, коли $ list> = 10); ii) щоб отримати точний вихід OP , ви machine_indented=${machine_indented/../ .}можете додати додатковий простір перед першим .. Як я вже сказав, педантичний.
тердон

привіт Чороба, чи можете ви, будь ласка, врахувати зауваження Тердона у своїй відповіді?
yael

@yael: Вам слід легко налаштувати рішення :-)
choroba

BTW - навіщо додати & раніше> / dev / null?
yael

8

for m in $listє zshсинтаксисом. В bashньому було б for i in "${list[@]}".

bashне має операторів прокладки. Можна робити набивання, printfале лише з пробілами, а не довільними символами. zshмає оператори padding.

#! /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}з правої -pad з довжиною 25 з пробілами або ${(r:25::string:)parameter}до правої -pad з будь-рядком замість простору.

Ми також використовуємо printf '%4s'для лівої -pad (x)прогалин. Ми могли використати ${(l:4:):-"($((++c)))"}натомість. Примітна відмінність полягає в тому, що якщо рядок довжиною більше 4 символів, вона ${(l)}буде усічена, тоді як вона переповнюється printf.


6

Специфікатор %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

2

З предметами, викраденими з відповіді @ 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

Я б це зробив з fpingі awk. На жаль, awk«S 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 хостів $list(100+ все одно його викручують). Альтернативи можна було б відкласти до тих пір , друк на END {}блоці, і для / регулярних виразів матчів / просто вставити ім'я хоста в одному з трьох масивів, наприклад ok, fail, unknown. або лише один асоціативний масив (наприклад hosts[hostname]="OK"). Тоді ви могли порахувати кількість рядків і скористатися нею, щоб визначити, якою шириною має бути поле лічильника ліній.

Я також вирішив розрізняти вихідні дані між невідомими хостами ( CONNECTION IMPOSSIBLE) та недоступними хостами ( CONNECTION FAIL).

sort -k3Чи не є обов'язковим, це просто групи вихід в fpingрезультаті ( «ім'я хоста живий», «ім'я хоста недосяжний» або «ім'я хоста: Ім'я або служба не відомі»). Без цього sort, невідомі хости завжди з'являться першими у висновку. Просто звичайно sortбез -k3сортування за іменем хоста.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.