bash + printf를 사용하여 특수 형식으로 인쇄

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

printfbash 스크립트에서 (또는 다른 명령)을 사용하여 다음 형식을 인쇄하려면 어떻게 해야 합니까 ?

 (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

답변1

매개변수 확장을 사용하여 %-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

답변2

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

이것충전재운영자 ${(r:25:)parameter}옳은- 공백이 있는 패드 길이 25 ${(r:25::string:)parameter}또는옳은- 공백 대신 임의의 문자열로 채웁니다.

우리는 또한 printf '%4s'사용합니다왼쪽- 공백으로 채웁니다 (x). 우리는 그것을 대신 사용할 수도 있었습니다 ${(l:4:):-"($((++c)))"}. 그러나 한 가지 중요한 차이점은 문자열이 4자를 초과하면 ${(l)}잘리고 오버플로가 발생한다는 것입니다 printf.

답변3

형식 %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

답변4

fping나는 and 로 할 것이다 awk. 불행하게도 awk' printf는 점으로 채울 수 없고 공백이나 0으로만 채울 수 있으므로 다음과 같은 함수를 작성해야 했습니다.

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개의 호스트가 있어도 형식이 엉망이 되지 않도록 괄호 안에 0으로 채워진 2자리 숫자를 사용합니다 $list(100+는 여전히 엉망입니다). 또 다른 접근 방식은 END {}블록이 발생할 때까지 인쇄를 지연하고 /regexp-matches/는 세 배열 중 하나에만 호스트 이름을 삽입하는 것입니다(예: ok, fail, ) unknown. 또는 단지 연관 배열(예 hosts[hostname]="OK": )입니다. 그런 다음 행 수를 계산하고 이를 사용하여 행 카운터 필드의 너비를 결정할 수 있습니다.

또한 출력에서 ​​알 수 없는 호스트( CONNECTION IMPOSSIBLE)와 연결할 수 없는 호스트( CONNECTION FAIL)를 구별하도록 결정했습니다.

선택 사항 이며 sort -k3결과 fping("호스트 이름이 활성 상태임", "호스트 이름에 연결할 수 없음" 또는 "호스트 이름: 이름 또는 서비스를 알 수 없음")에 따라 출력을 그룹화할 뿐입니다. 그렇지 않은 경우 sort알 수 없는 호스트가 항상 출력의 첫 번째로 나타납니다. 호스트 이름 별로 정렬이 sort없습니다 -k3.

관련 정보