Рисование гистограммы с выхода команды bash

У меня есть следующий вывод:

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, которая позволила бы мне это сделать?

Попробуйте это в perl :

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

ПОЯСНЕНИЯ:

  • -a – явный split() в массиве @F , мы получаем значения с $F[n]
  • x – указать perl для печати символа N раз
  • ($F[1] / 5) : здесь мы получаем число и делим его на 5 для довольно печатного результата

В perl :

 perl -pe 's/ (\d+)$/"="x$1/e' file 
  • e заставляет выражение оцениваться, поэтому я получаю = повторяющийся, используя значение $1 (число, сопоставляемое (\d+) ).
  • Вы можете сделать "="x($1\/3) вместо "="x$1 чтобы получить более короткие строки. (Истекает / поскольку мы находимся в середине команды подстановки.)

В bash (вдохновленный этим SO-ответом ):

 while read dn do printf "%s\t%${n}s\n" "$d" = | tr ' ' '=' done < test.txt 
  • printf накладывает вторую строку, используя пробелы, чтобы получить ширину $n ( %${n}s ), и я заменяю пробелы на = .
  • Столбцы разделены с помощью вкладки ( \t ), но вы можете сделать ее более column -ts'\t' по column -ts'\t' .
  • Вы можете использовать $((n/3)) вместо ${n} чтобы получить более короткие строки.

Другая версия:

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

Единственный недостаток, который я вижу, заключается в том, что вам нужно будет вывести вывод sed на что-то, если вы хотите уменьшить масштаб, иначе это самый чистый вариант. Если есть вероятность того, что ваш входной файл содержит один из [?* Вы должны привести команду w / set -f; ,

Легко с 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 

Как насчет:

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

Это поразило меня как забавную традиционную задачу командной строки. Вот мое решение для скрипта 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");}' 

Маленький сценарий выше предполагает, что данные находятся в файле, образно названном «данные».

Я не слишком доволен тем, что «пропустил его через sed и сортировку» – было бы необязательно, если бы ваш месяц и день месяца всегда имели 2 цифры, но это жизнь.

Кроме того, как историческое примечание, традиционные Unixes обычно поставлялись с утилитой построения командной строки, которая могла бы делать довольно уродливые графики и графики ASCII. Я не помню названия, но похоже, что GNU plotutils заменяет старую традиционную утилиту.

Хорошее упражнение здесь. Я сбросил данные в файл под названием «данные», потому что я очень изобретателен.

Ну, вы просили об этом в 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