bash + using printf เพื่อพิมพ์ในรูปแบบพิเศษ


12

ฉันเพิ่งเขียนสคริปต์ทุบตีต่อไปนี้เพื่อตรวจสอบการเข้าถึง 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(หรือคำสั่งอื่นใด) ในสคริปต์ทุบตีของฉันเพื่อพิมพ์รูปแบบต่อไปนี้ได้อย่างไร

 (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

คุณช่วยอธิบายวิธีแก้ปัญหาของคุณเป็นคำตอบได้
ไหม

คุณมีคำตอบแล้ว ;-)
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

ว้าวให้ฉันตรวจสอบและฉันจะอัปเดตเร็ว ๆ นี้ ..........................
yael

1
เฮ้ฉลาด! สองจุด pedantic: i) %2dคือการเพิ่มช่องว่างที่ไม่จำเป็นในวงเล็บ (แม้ว่ามันอาจจะมีประโยชน์เมื่อ $ list> = 10); ii) การที่จะได้รับของ OP ที่แน่นอนออกคุณอาจต้องการเพิ่มเพื่อเพิ่มพื้นที่พิเศษก่อนคนแรกmachine_indented=${machine_indented/../ .} .อย่างที่ฉันพูดอวด
terdon

สวัสดี Choroba คุณช่วยพิจารณาคำพูดของ terdon ในคำตอบของคุณได้ไหม?
yael

@yael: ตอนนี้มันเป็นเรื่องง่ายสำหรับคุณที่จะปรับแต่งโซลูชัน :-)
choroba

BTW - เหตุใดจึงต้องเพิ่ม & ก่อน> / dev / null
yael

8

for m in $listเป็นzshไวยากรณ์ ในมันจะเป็นbashfor 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}ไปขวา -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ไม่สามารถแผ่นมีจุดเท่านั้นที่มีช่องว่างหรือ zeroes ดังนั้นผมจึงต้องมีการเขียนฟังก์ชั่น:

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 หลักที่ไม่มีเบาะรองในวงเล็บเพื่อให้รูปแบบไม่ได้เมามากขึ้นหากมีโฮสต์ 10-99 ใน$list(100+ จะยังคงเมามัน) ทางเลือกที่จะชะลอการพิมพ์จนกว่าจะมีการEND {}บล็อกและสำหรับ / regexp ตรง / เพียงแค่ใส่ชื่อโฮสต์เป็นหนึ่งในสามของอาร์เรย์เช่นok, ,fail unknownหรืออาเรย์แบบเชื่อมโยงเดียว (เช่นhosts[hostname]="OK") จากนั้นคุณสามารถนับจำนวนบรรทัดและใช้เพื่อตัดสินใจว่าควรใช้ฟิลด์ตัวนับบรรทัดกว้างแค่ไหน

ฉันได้ตัดสินใจที่จะให้เอาต์พุตแยกความแตกต่างระหว่างโฮสต์ที่ไม่รู้จัก ( CONNECTION IMPOSSIBLE) และโฮสต์ที่ไม่สามารถเข้าถึงได้ ( CONNECTION FAIL)

sort -k3เป็นตัวเลือกก็แค่กลุ่มส่งออกโดยที่fpingผล ( "ชื่อโฮสต์ยังมีชีวิตอยู่", "ชื่อโฮสต์ไม่สามารถเข้าถึง" หรือ "ชื่อโฮสต์: ชื่อหรือบริการไม่เป็นที่รู้จัก") หากไม่มีsortโฮสต์ที่ไม่รู้จักจะปรากฏขึ้นเป็นอันดับแรกในเอาต์พุต เพียงแค่ธรรมดาsortโดยไม่ต้อง-k3จะเรียงตามชื่อโฮสต์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.