bash 명령 출력에서 ​​히스토그램 그리기


31

다음과 같은 출력이 있습니다.

2015/1/7    8
2015/1/8    49
2015/1/9    40
2015/1/10   337
2015/1/11   11
2015/1/12   3
2015/1/13   9
2015/1/14   102
2015/1/15   62
2015/1/16   10
2015/1/17   30
2015/1/18   30
2015/1/19   1
2015/1/20   3
2015/1/21   23
2015/1/22   12
2015/1/24   6
2015/1/25   3
2015/1/27   2
2015/1/28   16
2015/1/29   1
2015/2/1    12
2015/2/2    2
2015/2/3    1
2015/2/4    10
2015/2/5    13
2015/2/6    2
2015/2/9    2
2015/2/10   25
2015/2/11   1
2015/2/12   6
2015/2/13   12
2015/2/14   2
2015/2/16   8
2015/2/17   8
2015/2/20   1
2015/2/23   1
2015/2/27   1
2015/3/2    3
2015/3/3    2

그리고 히스토그램을 그리고 싶습니다

2015/1/7  ===
2015/1/8  ===========
2015/1/9  ==========
2015/1/10 ====================================================================
2015/1/11 ===
2015/1/11 =
...

내가 할 수있는 bash 명령이 있는지 알고 있습니까?


1
bashplotlib 는 훌륭한 솔루션입니다
Michael Mior

그것은 실제로 독립적 인 답변 대신 링크를 제공하는 위험 중 하나입니다. 경우 삭제 된 SO 답변이 유용합니다, 여기에 대한 답변으로 게시하시기 바랍니다.
Jeff Schaller

답변:


12

에서 이것을 시도하십시오 :

perl -lane 'print $F[0], "\t", "=" x ($F[1] / 5)' file

설명 :

  • -a명시되어 split()있는의 @F, 우리는 값을 배열 수$F[n]
  • x 펄에게 문자를 N 번 인쇄하도록 지시하는 것
  • ($F[1] / 5) : 여기에서 우리는 숫자를 얻고 5로 나눠서 예쁜 인쇄 출력을 얻습니다.

1
perl -lane 'print $F[0], "\t", $F[1], "\t", "=" x ($F[1] / 3 + 1)'정말 좋아 보인다 :) 고마워
Natim

12

에서 perl:

perl -pe 's/ (\d+)$/"="x$1/e' file
  • e식을 평가하게되므로 (의 숫자와 일치 =하는 값)을 사용하여 반복합니다 .$1(\d+)
  • 당신이 할 수있는 "="x($1\/3)대신에 "="x$1짧은 선을 얻을 수 있습니다. ( /대체 명령 중이기 때문에 이스케이프 처리되지 않았습니다.)

에서 bash( 이 SO 답변 에서 영감을 얻음 ) :

while read d n 
do 
    printf "%s\t%${n}s\n" "$d" = | tr ' ' '=' 
done < test.txt
  • printf공백을 사용하여 두 번째 문자열을 채우면 너비가 $n ( %${n}s)이되고 공백을로 바꿉니다 =.
  • 열은 탭 ( \t)을 사용하여 구분 되지만로 파이핑하여 더 예쁘게 만들 수 있습니다 column -ts'\t'.
  • 짧은 줄을 얻는 $((n/3))대신 사용할 수 있습니다 ${n}.

다른 버전 :

unset IFS; printf "%s\t%*s\n" $(sed 's/$/ =/' test.txt) | tr ' ' =

내가 볼 수있는 유일한 단점은 sed축소하려는 경우 출력을 무언가 로 파이프해야한다는 것 입니다. 그렇지 않으면 이것이 가장 깨끗한 옵션입니다. 입력 파일 중 하나를 포함 할 가능성이 있으면 [?*w / 명령을 실행해야합니다 set -f;.


2
쉘 솔루션도 보여주는 브라보. Perl 솔루션도 매우 깨끗합니다.
병아리

@mikeserv 원더풀! %*s비록 그것이 printfC 프로그래밍에서 배운 첫 번째 관련 트릭 이었지만 항상 잊어 버립니다 .
muru

printf(sed) | tr내가 알 수 있는 한 버전이 여기에서 작동하지 않습니다.
Natim

@Natim 여기 어디에?
muru

아마도 인수 길이의 @mikeserv 제한?
muru

6

쉽게 awk

awk '{$2=sprintf("%-*s", $2, ""); gsub(" ", "=", $2); printf("%-10s%s\n", $1, $2)}' file

2015/1/7 ========
2015/1/8 =================================================
2015/1/9 ========================================
..
..

또는 내가 좋아하는 프로그래밍 언어로

python3 -c 'import sys
for line in sys.stdin:
  data, width = line.split()
  print("{:<10}{:=<{width}}".format(data, "", width=width))' <file

3

어때요 :

#! /bin/bash
histo="======================================================================+"

read datewd value

while [ -n "$datewd" ] ; do
   # Use a default width of 70 for the histogram
   echo -n "$datewd      "
   echo ${histo:0:$value}

   read datewd value
done

어느 생산 :

~/bash $./histogram.sh < histdata.txt
2015/1/7    ========
2015/1/8    =================================================
2015/1/9    ========================================
2015/1/10   ======================================================================+
2015/1/11   ===========
2015/1/12   ===
2015/1/13   =========
2015/1/14   ======================================================================+
2015/1/15   ==============================================================
2015/1/16   ==========
2015/1/17   ==============================
2015/1/18   ==============================
2015/1/19   =
2015/1/20   ===
2015/1/21   =======================
2015/1/22   ============
2015/1/24   ======
2015/1/25   ===
2015/1/27   ==
2015/1/28   ================
2015/1/29   =
2015/2/1    ============
2015/2/2    ==
2015/2/3    =
2015/2/4    ==========
2015/2/5    =============
2015/2/6    ==
2015/2/9    ==
2015/2/10   =========================
2015/2/11   =
2015/2/12   ======
2015/2/13   ============
2015/2/14   ==
2015/2/16   ========
2015/2/17   ========
2015/2/20   =
2015/2/23   =
2015/2/27   =
2015/3/2    ===
2015/3/3    ==
~/bash $

1

이것은 재미있는 전통적인 명령 줄 문제로 나를 놀라게했습니다. 내 bash스크립트 솔루션은 다음과 같습니다 .

awk '{if (count[$1]){count[$1] += $2} else {count[$1] = $2}} \
        END{for (year in count) {print year, count[year];}}' data |
sed -e 's/\// /g' | sort -k1,1n -k2,2n -k3,3n |
awk '{printf("%d/%d/%d\t", $1,$2,$3); for (i=0;i<$4;++i) {printf("=")}; printf("\n");}'

위의 작은 스크립트는 데이터가 상상적으로 "data"라는 파일에 있다고 가정합니다.

"sed and sort를 통해 실행"행에 너무 만족하지 않습니다. 월과 일에 항상 2 자리가 있으면 불필요합니다.

또한 역사적 유서로 전통적인 유닉스는 상당히 추악한 ASCII 그래프와 플롯을 수행 할 수있는 명령 줄 플로팅 유틸리티를 제공했습니다. 이름을 기억할 수 없지만 GNU plotutils 가 기존의 기존 유틸리티를 대체하는 것처럼 보입니다 .


그렇지 if ($1 in count) ...않습니까?
muru

1
@muru-어느 쪽이든 작동하는 것 같습니다. 그러나 "else"절에서 오타가 발견되었습니다. 감사.
Bruce Ediger

1

좋은 운동입니다. 상상력이 풍부하기 때문에 "data"라는 파일에 데이터를 덤프했습니다.

글쎄, 당신은 bash로 요청했습니다 ... 여기는 순수한 bash입니다.

cat data | while read date i; do printf "%-10s " $date; for x in $(seq 1 $i); do echo -n "="; done; echo; done

awk가 더 나은 옵션입니다.

awk '{ s=" ";while ($2-->0) s=s"=";printf "%-10s %s\n",$1,s }' data

파일을 사용하는 대신 awk를 통해 데이터를 파이프 할 수 있습니까?
Natim

예, 어느 쪽이든 같은 것입니다. "고양이 데이터 |"를 추가하기 만하면됩니다. 처음에는 bash 비트 또는 "<data"에 대한 것처럼. 또는 파일을 지정하지 않고 awk 부분을 가져 와서 데이터를 붙여 넣고 ctrl-D를 누르십시오. 파일을 지정하면 해당 파일이 stdin으로 취급되며 게으 르기 때문에 데이터 파일을 계속 복사하여 붙여 넣기를 원하지 않습니다.
Falsenames

1
사실, 나는 이것을 동료에게 연결하면서 질문을 다시 읽었습니다 ... 당신은 데이터 파일이 아니라 "출력"을 가지고 있다고 말했습니다. 따라서 해당 보고서를 생성하는 모든 작업을 실행 한 다음 awk로 파이프하면 완료됩니다. 파이프는 마지막 명령의 출력을 다음 명령의 입력 소스로 지정합니다.
Falsenames

0

이 시도:

while read value count; do
    printf '%s:\t%s\n' "${value}" "$(printf "%${count}s" | tr ' ' '=')"
done <path/to/my-output

까다로운 부분은 바의 구성입니다. 나는 여기에 SO 답변 을 위임 printf하고 tr좋아 함으로써 그것을한다 .

보너스로 POSIX sh호환입니다.

참고 문헌 :

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.