bash + sử dụng printf để in ở định dạng đặc biệt


12

Tôi vừa viết đoạn mã bash sau để kiểm tra quyền truy cập ping trên danh sách các máy 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

Bản in này:

 (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

Làm cách nào tôi có thể sử dụng printf(hoặc bất kỳ lệnh nào khác) trong tập lệnh bash của mình để in định dạng sau?

 (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

Bạn có thể làm một phép tính, $TOTAL (length) - $MASHINE (length)để có được số lượng dấu chấm. Sau đó sử dụng printf '.%.s' {1..$DOTS}trong mỗi vòng lặp lặp. Một cái gì đó như thế này tôi nghĩ sẽ làm việc.
coffeMug

bạn có thể vui lòng mô tả giải pháp của bạn như câu trả lời
yael

Bạn đã có một câu trả lời. ;-)
coffeMug

Câu trả lời:


19

Sử dụng mở rộng tham số để thay thế khoảng trắng do %-sdấu chấm:

#!/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, hãy để tôi kiểm tra và tôi sẽ cập nhật sớm ..........................
yael

1
Heh, thông minh! Một vài điểm phạm vi: i) việc %2dthêm một khoảng trống không cần thiết bên trong dấu ngoặc đơn (mặc dù nó có thể hữu ích khi $ list> = 10); ii) để có được đầu ra chính xác của OP , bạn có thể muốn thêm machine_indented=${machine_indented/../ .}để thêm một khoảng trắng trước đầu tiên .. Như tôi đã nói, pedantic.
terdon

chào Choroba, bạn có thể vui lòng xem xét nhận xét terdon trong câu trả lời của bạn không?
yael

@yael: Bây giờ bạn có thể dễ dàng điều chỉnh giải pháp :-)
choroba

BTW - tại sao phải thêm & trước> / dev / null?
yael

8

for m in $listzshcú pháp. Trong bashđó sẽ là for i in "${list[@]}".

bashkhông có toán tử đệm. Bạn có thể thực hiện đệm với printfnhưng chỉ với khoảng trắng, không phải ký tự tùy ý. zshcó toán tử đệm.

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

Các đệm điều hành là ${(r:25:)parameter}để đúng -pad với chiều dài 25 với không gian hoặc ${(r:25::string:)parameter}để ngay -pad với bất kỳ chuỗi thay vì không gian.

Chúng tôi cũng sử dụng printf '%4s'để trái -pad sự (x)với không gian. Chúng tôi có thể đã sử dụng ${(l:4:):-"($((++c)))"}thay thế. Một sự khác biệt đáng chú ý là nếu chuỗi dài hơn 4 ký tự, ${(l)}sẽ cắt bớt nó, trong khi nó sẽ tràn ra printf.


6

Trình %sxác định định dạng có thể có độ chính xác ( %.20sví dụ) và giống như khi bạn muốn xuất giá trị float đến độ chính xác nhất định ( %.4fví dụ), đầu ra sẽ có nhiều nhất là nhiều ký tự từ đối số chuỗi đã cho.

Vì vậy, tạo một chuỗi chứa tên máy và đủ số chấm để hết chấm:

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

Đầu ra:

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

2

Với những thứ bị đánh cắp từ câu trả lời của @ 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

Tôi sẽ làm điều đó với fpingawk. Thật không may, awkprintfkhông thể pad với dấu chấm, chỉ có khoảng trắng hoặc zero vì vậy tôi phải viết một hàm:

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

Tôi đang sử dụng các số có 2 chữ số được đệm bằng 0 trong ngoặc đơn để định dạng không bị sai lệch nếu có 10-99 máy chủ lưu trữ $list(100+ vẫn sẽ làm hỏng nó). Việc thay thế sẽ được trì hoãn cho đến khi in một END {}khối, và cho / regexp-diêm / chỉ chèn tên máy vào một trong ba mảng, ví dụ như ok, fail, unknown. hoặc chỉ một mảng kết hợp (ví dụ hosts[hostname]="OK"). Sau đó, bạn có thể đếm số lượng dòng và sử dụng số đó để quyết định độ rộng của trường bộ đếm dòng.

Tôi cũng đã quyết định phân biệt đầu ra giữa các máy chủ không xác định ( CONNECTION IMPOSSIBLE) và máy chủ không thể truy cập ( CONNECTION FAIL).

Đây sort -k3là tùy chọn, nó chỉ nhóm đầu ra theo fpingkết quả ("tên máy chủ còn sống", "tên máy chủ không thể truy cập được" hoặc "tên máy chủ: Tên hoặc dịch vụ không được biết"). Không có sort, các máy chủ không xác định sẽ luôn xuất hiện đầu tiên trong đầu ra. Chỉ đơn giản là sortkhông có ý -k3chí sắp xếp theo tên máy chủ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.