Drawing a histogram from a bash command output
Clash Royale CLAN TAG#URR8PPP
up vote
25
down vote
favorite
I have the following output:
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
And I'd like to draw a histogram
2015/1/7 ===
2015/1/8 ===========
2015/1/9 ==========
2015/1/10 ====================================================================
2015/1/11 ===
2015/1/11 =
...
Do you know if there is a bash command that would let me do that?
bash
migrated from serverfault.com Jan 6 '15 at 16:50
This question came from our site for system and network administrators.
add a comment |Â
up vote
25
down vote
favorite
I have the following output:
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
And I'd like to draw a histogram
2015/1/7 ===
2015/1/8 ===========
2015/1/9 ==========
2015/1/10 ====================================================================
2015/1/11 ===
2015/1/11 =
...
Do you know if there is a bash command that would let me do that?
bash
migrated from serverfault.com Jan 6 '15 at 16:50
This question came from our site for system and network administrators.
1
stackoverflow.com/questions/6949332/â¦
â ceejayoz
Jan 6 '15 at 16:52
add a comment |Â
up vote
25
down vote
favorite
up vote
25
down vote
favorite
I have the following output:
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
And I'd like to draw a histogram
2015/1/7 ===
2015/1/8 ===========
2015/1/9 ==========
2015/1/10 ====================================================================
2015/1/11 ===
2015/1/11 =
...
Do you know if there is a bash command that would let me do that?
bash
I have the following output:
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
And I'd like to draw a histogram
2015/1/7 ===
2015/1/8 ===========
2015/1/9 ==========
2015/1/10 ====================================================================
2015/1/11 ===
2015/1/11 =
...
Do you know if there is a bash command that would let me do that?
bash
bash
edited 48 mins ago
Michael Mior
22527
22527
asked Jan 6 '15 at 16:45
Natim
252138
252138
migrated from serverfault.com Jan 6 '15 at 16:50
This question came from our site for system and network administrators.
migrated from serverfault.com Jan 6 '15 at 16:50
This question came from our site for system and network administrators.
1
stackoverflow.com/questions/6949332/â¦
â ceejayoz
Jan 6 '15 at 16:52
add a comment |Â
1
stackoverflow.com/questions/6949332/â¦
â ceejayoz
Jan 6 '15 at 16:52
1
1
stackoverflow.com/questions/6949332/â¦
â ceejayoz
Jan 6 '15 at 16:52
stackoverflow.com/questions/6949332/â¦
â ceejayoz
Jan 6 '15 at 16:52
add a comment |Â
7 Answers
7
active
oldest
votes
up vote
9
down vote
accepted
Try this in perl :
perl -lane 'print $F[0], "t", "=" x ($F[1] / 5)' file
EXPLANATIONS:
-a
is an explicitsplit()
in@F
array, we get the values with$F[n]
x
is to tell perl to print a character N times($F[1] / 5)
: here we get the number and divide it by 5 for a pretty print output
1
perl -lane 'print $F[0], "t", $F[1], "t", "=" x ($F[1] / 3 + 1)'
It looks really great :) thanks
â Natim
Jan 7 '15 at 9:05
add a comment |Â
up vote
10
down vote
In perl
:
perl -pe 's/ (d+)$/"="x$1/e' file
e
causes the expression to be evaluated, so I get=
repeated using the value of$1
(the number matched by(d+)
).- You could do
"="x($1/3)
instead of"="x$1
to get shorter lines. (The/
is escaped since we're in the middle of a substitution command.)
In bash
(inspired from this SO answer):
while read d n
do
printf "%st%$nsn" "$d" = | tr ' ' '='
done < test.txt
printf
pads the second string using spaces to get a width of$n
(%$ns
), and I replace the spaces with=
.- The columns are delimited using a tab (
t
), but you can make it prettier by piping tocolumn -ts't'
. - You could use
$((n/3))
instead of$n
to get shorter lines.
Another version:
unset IFS; printf "%st%*sn" $(sed 's/$/ =/' test.txt) | tr ' ' =
The only drawback I can see is that you'll need to pipe sed
's output to something if you want to scale down, otherwise this is the cleanest option. If there is a chance of your input file containing one of [?*
you should lead the command w/ set -f;
.
2
Bravo for showing a shell solution too. Your Perl solution is very clean as well.
â chicks
Jan 6 '15 at 17:38
@mikeserv Wonderful! I always forget%*s
even though it was the firstprintf
-related trick I learnt in C programming.
â muru
Jan 7 '15 at 2:22
Theprintf(sed) | tr
version doesn't works here as far as I can tell.
â Natim
Jan 7 '15 at 9:03
@Natim here being where?
â muru
Jan 7 '15 at 10:42
@mikeserv limitations in argument length perhaps?
â muru
Jan 7 '15 at 11:55
 |Â
show 7 more comments
up vote
6
down vote
Easy with awk
awk '$2=sprintf("%-*s", $2, ""); gsub(" ", "=", $2); printf("%-10s%sn", $1, $2)' file
2015/1/7 ========
2015/1/8 =================================================
2015/1/9 ========================================
..
..
Or with my favourite programming language
python3 -c 'import sys
for line in sys.stdin:
data, width = line.split()
print(":<10:=<width".format(data, "", width=width))' <file
add a comment |Â
up vote
3
down vote
How about:
#! /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
Which produces:
~/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 $
add a comment |Â
up vote
1
down vote
This struck me as a fun traditional command line problem. Here's my bash
script solution:
awk 'if (count[$1])count[$1] += $2 else count[$1] = $2
ENDfor (year in count) print year, count[year];' data |
sed -e 's/// /g' | sort -k1,1n -k2,2n -k3,3n |
awk 'printf("%d/%d/%dt", $1,$2,$3); for (i=0;i<$4;++i) printf("="); printf("n");'
The little script above assumes the data is in a file imaginatively named "data".
I'm not too happy with the "run it through sed and sort" line - it would be unnecessary if your month and day-of-month always had 2 digits, but that's life.
Also, as a historical note, traditional Unixes used to come with a command line plotting utility that could do fairly ugly ASCII graphs and plots. I can't remember the name, but it looks like GNU plotutils replace the old traditional utility.
Shouldn't that beif ($1 in count) ...
?
â muru
Jan 6 '15 at 18:58
1
@muru - seems to work either way. However, I did find a typo in the "else" clause. Thanks.
â Bruce Ediger
Jan 6 '15 at 19:19
add a comment |Â
up vote
1
down vote
Nice exercise here. I dumped the data in a file called "data" because I am very imaginative.
Well, you asked for it in bash... here it is in pure bash.
cat data | while read date i; do printf "%-10s " $date; for x in $(seq 1 $i); do echo -n "="; done; echo; done
awk is a better option.
awk ' s=" ";while ($2-->0) s=s"=";printf "%-10s %sn",$1,s ' data
Can you pipe the data through awk instead of using a file?
â Natim
Jan 7 '15 at 8:52
Yes, it's the same thing either way. Just add a "cat data |" at the beginning like I had for the bash bits, or a "<data" at the end. Or you can even just have the awk part without a file specified, paste in the data and hit ctrl-D at the end. Specifying the file just treats that file as stdin, and I didn't want to keep copying and pasting the datafile because I'm lazy.
â Falsenames
Jan 7 '15 at 16:47
1
Actually, I just reread the question while linking this to a coworker... you said you had "output", not a data file. So you can just run whatever is creating that report, then pipe it to awk, and you're done. Pipes just direct output of the last command as the source of input for the next command.
â Falsenames
Jan 7 '15 at 17:06
add a comment |Â
up vote
0
down vote
Try this:
while read value count; do
printf '%s:t%sn' "$value" "$(printf "%$counts" | tr ' ' '=')"
done <path/to/my-output
The only tricky part is the construction of the bar. I do it here by delegating to printf
and tr
like this SO answer.
As a bonus, it's POSIX-sh
-compliant.
References:
- https://stackoverflow.com/questions/5349718/how-can-i-repeat-a-character-in-bash/5349796#5349796
- https://www.unix.com/man-page/posix/1P/printf/
- https://www.unix.com/man-page/posix/1P/tr/
add a comment |Â
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
9
down vote
accepted
Try this in perl :
perl -lane 'print $F[0], "t", "=" x ($F[1] / 5)' file
EXPLANATIONS:
-a
is an explicitsplit()
in@F
array, we get the values with$F[n]
x
is to tell perl to print a character N times($F[1] / 5)
: here we get the number and divide it by 5 for a pretty print output
1
perl -lane 'print $F[0], "t", $F[1], "t", "=" x ($F[1] / 3 + 1)'
It looks really great :) thanks
â Natim
Jan 7 '15 at 9:05
add a comment |Â
up vote
9
down vote
accepted
Try this in perl :
perl -lane 'print $F[0], "t", "=" x ($F[1] / 5)' file
EXPLANATIONS:
-a
is an explicitsplit()
in@F
array, we get the values with$F[n]
x
is to tell perl to print a character N times($F[1] / 5)
: here we get the number and divide it by 5 for a pretty print output
1
perl -lane 'print $F[0], "t", $F[1], "t", "=" x ($F[1] / 3 + 1)'
It looks really great :) thanks
â Natim
Jan 7 '15 at 9:05
add a comment |Â
up vote
9
down vote
accepted
up vote
9
down vote
accepted
Try this in perl :
perl -lane 'print $F[0], "t", "=" x ($F[1] / 5)' file
EXPLANATIONS:
-a
is an explicitsplit()
in@F
array, we get the values with$F[n]
x
is to tell perl to print a character N times($F[1] / 5)
: here we get the number and divide it by 5 for a pretty print output
Try this in perl :
perl -lane 'print $F[0], "t", "=" x ($F[1] / 5)' file
EXPLANATIONS:
-a
is an explicitsplit()
in@F
array, we get the values with$F[n]
x
is to tell perl to print a character N times($F[1] / 5)
: here we get the number and divide it by 5 for a pretty print output
edited Jan 7 '15 at 1:11
answered Jan 6 '15 at 16:54
Gilles Quenot
15.8k13649
15.8k13649
1
perl -lane 'print $F[0], "t", $F[1], "t", "=" x ($F[1] / 3 + 1)'
It looks really great :) thanks
â Natim
Jan 7 '15 at 9:05
add a comment |Â
1
perl -lane 'print $F[0], "t", $F[1], "t", "=" x ($F[1] / 3 + 1)'
It looks really great :) thanks
â Natim
Jan 7 '15 at 9:05
1
1
perl -lane 'print $F[0], "t", $F[1], "t", "=" x ($F[1] / 3 + 1)'
It looks really great :) thanksâ Natim
Jan 7 '15 at 9:05
perl -lane 'print $F[0], "t", $F[1], "t", "=" x ($F[1] / 3 + 1)'
It looks really great :) thanksâ Natim
Jan 7 '15 at 9:05
add a comment |Â
up vote
10
down vote
In perl
:
perl -pe 's/ (d+)$/"="x$1/e' file
e
causes the expression to be evaluated, so I get=
repeated using the value of$1
(the number matched by(d+)
).- You could do
"="x($1/3)
instead of"="x$1
to get shorter lines. (The/
is escaped since we're in the middle of a substitution command.)
In bash
(inspired from this SO answer):
while read d n
do
printf "%st%$nsn" "$d" = | tr ' ' '='
done < test.txt
printf
pads the second string using spaces to get a width of$n
(%$ns
), and I replace the spaces with=
.- The columns are delimited using a tab (
t
), but you can make it prettier by piping tocolumn -ts't'
. - You could use
$((n/3))
instead of$n
to get shorter lines.
Another version:
unset IFS; printf "%st%*sn" $(sed 's/$/ =/' test.txt) | tr ' ' =
The only drawback I can see is that you'll need to pipe sed
's output to something if you want to scale down, otherwise this is the cleanest option. If there is a chance of your input file containing one of [?*
you should lead the command w/ set -f;
.
2
Bravo for showing a shell solution too. Your Perl solution is very clean as well.
â chicks
Jan 6 '15 at 17:38
@mikeserv Wonderful! I always forget%*s
even though it was the firstprintf
-related trick I learnt in C programming.
â muru
Jan 7 '15 at 2:22
Theprintf(sed) | tr
version doesn't works here as far as I can tell.
â Natim
Jan 7 '15 at 9:03
@Natim here being where?
â muru
Jan 7 '15 at 10:42
@mikeserv limitations in argument length perhaps?
â muru
Jan 7 '15 at 11:55
 |Â
show 7 more comments
up vote
10
down vote
In perl
:
perl -pe 's/ (d+)$/"="x$1/e' file
e
causes the expression to be evaluated, so I get=
repeated using the value of$1
(the number matched by(d+)
).- You could do
"="x($1/3)
instead of"="x$1
to get shorter lines. (The/
is escaped since we're in the middle of a substitution command.)
In bash
(inspired from this SO answer):
while read d n
do
printf "%st%$nsn" "$d" = | tr ' ' '='
done < test.txt
printf
pads the second string using spaces to get a width of$n
(%$ns
), and I replace the spaces with=
.- The columns are delimited using a tab (
t
), but you can make it prettier by piping tocolumn -ts't'
. - You could use
$((n/3))
instead of$n
to get shorter lines.
Another version:
unset IFS; printf "%st%*sn" $(sed 's/$/ =/' test.txt) | tr ' ' =
The only drawback I can see is that you'll need to pipe sed
's output to something if you want to scale down, otherwise this is the cleanest option. If there is a chance of your input file containing one of [?*
you should lead the command w/ set -f;
.
2
Bravo for showing a shell solution too. Your Perl solution is very clean as well.
â chicks
Jan 6 '15 at 17:38
@mikeserv Wonderful! I always forget%*s
even though it was the firstprintf
-related trick I learnt in C programming.
â muru
Jan 7 '15 at 2:22
Theprintf(sed) | tr
version doesn't works here as far as I can tell.
â Natim
Jan 7 '15 at 9:03
@Natim here being where?
â muru
Jan 7 '15 at 10:42
@mikeserv limitations in argument length perhaps?
â muru
Jan 7 '15 at 11:55
 |Â
show 7 more comments
up vote
10
down vote
up vote
10
down vote
In perl
:
perl -pe 's/ (d+)$/"="x$1/e' file
e
causes the expression to be evaluated, so I get=
repeated using the value of$1
(the number matched by(d+)
).- You could do
"="x($1/3)
instead of"="x$1
to get shorter lines. (The/
is escaped since we're in the middle of a substitution command.)
In bash
(inspired from this SO answer):
while read d n
do
printf "%st%$nsn" "$d" = | tr ' ' '='
done < test.txt
printf
pads the second string using spaces to get a width of$n
(%$ns
), and I replace the spaces with=
.- The columns are delimited using a tab (
t
), but you can make it prettier by piping tocolumn -ts't'
. - You could use
$((n/3))
instead of$n
to get shorter lines.
Another version:
unset IFS; printf "%st%*sn" $(sed 's/$/ =/' test.txt) | tr ' ' =
The only drawback I can see is that you'll need to pipe sed
's output to something if you want to scale down, otherwise this is the cleanest option. If there is a chance of your input file containing one of [?*
you should lead the command w/ set -f;
.
In perl
:
perl -pe 's/ (d+)$/"="x$1/e' file
e
causes the expression to be evaluated, so I get=
repeated using the value of$1
(the number matched by(d+)
).- You could do
"="x($1/3)
instead of"="x$1
to get shorter lines. (The/
is escaped since we're in the middle of a substitution command.)
In bash
(inspired from this SO answer):
while read d n
do
printf "%st%$nsn" "$d" = | tr ' ' '='
done < test.txt
printf
pads the second string using spaces to get a width of$n
(%$ns
), and I replace the spaces with=
.- The columns are delimited using a tab (
t
), but you can make it prettier by piping tocolumn -ts't'
. - You could use
$((n/3))
instead of$n
to get shorter lines.
Another version:
unset IFS; printf "%st%*sn" $(sed 's/$/ =/' test.txt) | tr ' ' =
The only drawback I can see is that you'll need to pipe sed
's output to something if you want to scale down, otherwise this is the cleanest option. If there is a chance of your input file containing one of [?*
you should lead the command w/ set -f;
.
edited May 23 '17 at 12:40
Communityâ¦
1
1
answered Jan 6 '15 at 16:58
muru
34.5k579151
34.5k579151
2
Bravo for showing a shell solution too. Your Perl solution is very clean as well.
â chicks
Jan 6 '15 at 17:38
@mikeserv Wonderful! I always forget%*s
even though it was the firstprintf
-related trick I learnt in C programming.
â muru
Jan 7 '15 at 2:22
Theprintf(sed) | tr
version doesn't works here as far as I can tell.
â Natim
Jan 7 '15 at 9:03
@Natim here being where?
â muru
Jan 7 '15 at 10:42
@mikeserv limitations in argument length perhaps?
â muru
Jan 7 '15 at 11:55
 |Â
show 7 more comments
2
Bravo for showing a shell solution too. Your Perl solution is very clean as well.
â chicks
Jan 6 '15 at 17:38
@mikeserv Wonderful! I always forget%*s
even though it was the firstprintf
-related trick I learnt in C programming.
â muru
Jan 7 '15 at 2:22
Theprintf(sed) | tr
version doesn't works here as far as I can tell.
â Natim
Jan 7 '15 at 9:03
@Natim here being where?
â muru
Jan 7 '15 at 10:42
@mikeserv limitations in argument length perhaps?
â muru
Jan 7 '15 at 11:55
2
2
Bravo for showing a shell solution too. Your Perl solution is very clean as well.
â chicks
Jan 6 '15 at 17:38
Bravo for showing a shell solution too. Your Perl solution is very clean as well.
â chicks
Jan 6 '15 at 17:38
@mikeserv Wonderful! I always forget
%*s
even though it was the first printf
-related trick I learnt in C programming.â muru
Jan 7 '15 at 2:22
@mikeserv Wonderful! I always forget
%*s
even though it was the first printf
-related trick I learnt in C programming.â muru
Jan 7 '15 at 2:22
The
printf(sed) | tr
version doesn't works here as far as I can tell.â Natim
Jan 7 '15 at 9:03
The
printf(sed) | tr
version doesn't works here as far as I can tell.â Natim
Jan 7 '15 at 9:03
@Natim here being where?
â muru
Jan 7 '15 at 10:42
@Natim here being where?
â muru
Jan 7 '15 at 10:42
@mikeserv limitations in argument length perhaps?
â muru
Jan 7 '15 at 11:55
@mikeserv limitations in argument length perhaps?
â muru
Jan 7 '15 at 11:55
 |Â
show 7 more comments
up vote
6
down vote
Easy with awk
awk '$2=sprintf("%-*s", $2, ""); gsub(" ", "=", $2); printf("%-10s%sn", $1, $2)' file
2015/1/7 ========
2015/1/8 =================================================
2015/1/9 ========================================
..
..
Or with my favourite programming language
python3 -c 'import sys
for line in sys.stdin:
data, width = line.split()
print(":<10:=<width".format(data, "", width=width))' <file
add a comment |Â
up vote
6
down vote
Easy with awk
awk '$2=sprintf("%-*s", $2, ""); gsub(" ", "=", $2); printf("%-10s%sn", $1, $2)' file
2015/1/7 ========
2015/1/8 =================================================
2015/1/9 ========================================
..
..
Or with my favourite programming language
python3 -c 'import sys
for line in sys.stdin:
data, width = line.split()
print(":<10:=<width".format(data, "", width=width))' <file
add a comment |Â
up vote
6
down vote
up vote
6
down vote
Easy with awk
awk '$2=sprintf("%-*s", $2, ""); gsub(" ", "=", $2); printf("%-10s%sn", $1, $2)' file
2015/1/7 ========
2015/1/8 =================================================
2015/1/9 ========================================
..
..
Or with my favourite programming language
python3 -c 'import sys
for line in sys.stdin:
data, width = line.split()
print(":<10:=<width".format(data, "", width=width))' <file
Easy with awk
awk '$2=sprintf("%-*s", $2, ""); gsub(" ", "=", $2); printf("%-10s%sn", $1, $2)' file
2015/1/7 ========
2015/1/8 =================================================
2015/1/9 ========================================
..
..
Or with my favourite programming language
python3 -c 'import sys
for line in sys.stdin:
data, width = line.split()
print(":<10:=<width".format(data, "", width=width))' <file
edited Jan 7 '15 at 14:10
answered Jan 6 '15 at 22:00
iruvar
11.7k62959
11.7k62959
add a comment |Â
add a comment |Â
up vote
3
down vote
How about:
#! /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
Which produces:
~/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 $
add a comment |Â
up vote
3
down vote
How about:
#! /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
Which produces:
~/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 $
add a comment |Â
up vote
3
down vote
up vote
3
down vote
How about:
#! /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
Which produces:
~/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 $
How about:
#! /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
Which produces:
~/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 $
answered Jan 8 '15 at 14:47
Robert Nix
312
312
add a comment |Â
add a comment |Â
up vote
1
down vote
This struck me as a fun traditional command line problem. Here's my bash
script solution:
awk 'if (count[$1])count[$1] += $2 else count[$1] = $2
ENDfor (year in count) print year, count[year];' data |
sed -e 's/// /g' | sort -k1,1n -k2,2n -k3,3n |
awk 'printf("%d/%d/%dt", $1,$2,$3); for (i=0;i<$4;++i) printf("="); printf("n");'
The little script above assumes the data is in a file imaginatively named "data".
I'm not too happy with the "run it through sed and sort" line - it would be unnecessary if your month and day-of-month always had 2 digits, but that's life.
Also, as a historical note, traditional Unixes used to come with a command line plotting utility that could do fairly ugly ASCII graphs and plots. I can't remember the name, but it looks like GNU plotutils replace the old traditional utility.
Shouldn't that beif ($1 in count) ...
?
â muru
Jan 6 '15 at 18:58
1
@muru - seems to work either way. However, I did find a typo in the "else" clause. Thanks.
â Bruce Ediger
Jan 6 '15 at 19:19
add a comment |Â
up vote
1
down vote
This struck me as a fun traditional command line problem. Here's my bash
script solution:
awk 'if (count[$1])count[$1] += $2 else count[$1] = $2
ENDfor (year in count) print year, count[year];' data |
sed -e 's/// /g' | sort -k1,1n -k2,2n -k3,3n |
awk 'printf("%d/%d/%dt", $1,$2,$3); for (i=0;i<$4;++i) printf("="); printf("n");'
The little script above assumes the data is in a file imaginatively named "data".
I'm not too happy with the "run it through sed and sort" line - it would be unnecessary if your month and day-of-month always had 2 digits, but that's life.
Also, as a historical note, traditional Unixes used to come with a command line plotting utility that could do fairly ugly ASCII graphs and plots. I can't remember the name, but it looks like GNU plotutils replace the old traditional utility.
Shouldn't that beif ($1 in count) ...
?
â muru
Jan 6 '15 at 18:58
1
@muru - seems to work either way. However, I did find a typo in the "else" clause. Thanks.
â Bruce Ediger
Jan 6 '15 at 19:19
add a comment |Â
up vote
1
down vote
up vote
1
down vote
This struck me as a fun traditional command line problem. Here's my bash
script solution:
awk 'if (count[$1])count[$1] += $2 else count[$1] = $2
ENDfor (year in count) print year, count[year];' data |
sed -e 's/// /g' | sort -k1,1n -k2,2n -k3,3n |
awk 'printf("%d/%d/%dt", $1,$2,$3); for (i=0;i<$4;++i) printf("="); printf("n");'
The little script above assumes the data is in a file imaginatively named "data".
I'm not too happy with the "run it through sed and sort" line - it would be unnecessary if your month and day-of-month always had 2 digits, but that's life.
Also, as a historical note, traditional Unixes used to come with a command line plotting utility that could do fairly ugly ASCII graphs and plots. I can't remember the name, but it looks like GNU plotutils replace the old traditional utility.
This struck me as a fun traditional command line problem. Here's my bash
script solution:
awk 'if (count[$1])count[$1] += $2 else count[$1] = $2
ENDfor (year in count) print year, count[year];' data |
sed -e 's/// /g' | sort -k1,1n -k2,2n -k3,3n |
awk 'printf("%d/%d/%dt", $1,$2,$3); for (i=0;i<$4;++i) printf("="); printf("n");'
The little script above assumes the data is in a file imaginatively named "data".
I'm not too happy with the "run it through sed and sort" line - it would be unnecessary if your month and day-of-month always had 2 digits, but that's life.
Also, as a historical note, traditional Unixes used to come with a command line plotting utility that could do fairly ugly ASCII graphs and plots. I can't remember the name, but it looks like GNU plotutils replace the old traditional utility.
edited Jan 6 '15 at 19:20
answered Jan 6 '15 at 18:50
Bruce Ediger
34.3k565118
34.3k565118
Shouldn't that beif ($1 in count) ...
?
â muru
Jan 6 '15 at 18:58
1
@muru - seems to work either way. However, I did find a typo in the "else" clause. Thanks.
â Bruce Ediger
Jan 6 '15 at 19:19
add a comment |Â
Shouldn't that beif ($1 in count) ...
?
â muru
Jan 6 '15 at 18:58
1
@muru - seems to work either way. However, I did find a typo in the "else" clause. Thanks.
â Bruce Ediger
Jan 6 '15 at 19:19
Shouldn't that be
if ($1 in count) ...
?â muru
Jan 6 '15 at 18:58
Shouldn't that be
if ($1 in count) ...
?â muru
Jan 6 '15 at 18:58
1
1
@muru - seems to work either way. However, I did find a typo in the "else" clause. Thanks.
â Bruce Ediger
Jan 6 '15 at 19:19
@muru - seems to work either way. However, I did find a typo in the "else" clause. Thanks.
â Bruce Ediger
Jan 6 '15 at 19:19
add a comment |Â
up vote
1
down vote
Nice exercise here. I dumped the data in a file called "data" because I am very imaginative.
Well, you asked for it in bash... here it is in pure bash.
cat data | while read date i; do printf "%-10s " $date; for x in $(seq 1 $i); do echo -n "="; done; echo; done
awk is a better option.
awk ' s=" ";while ($2-->0) s=s"=";printf "%-10s %sn",$1,s ' data
Can you pipe the data through awk instead of using a file?
â Natim
Jan 7 '15 at 8:52
Yes, it's the same thing either way. Just add a "cat data |" at the beginning like I had for the bash bits, or a "<data" at the end. Or you can even just have the awk part without a file specified, paste in the data and hit ctrl-D at the end. Specifying the file just treats that file as stdin, and I didn't want to keep copying and pasting the datafile because I'm lazy.
â Falsenames
Jan 7 '15 at 16:47
1
Actually, I just reread the question while linking this to a coworker... you said you had "output", not a data file. So you can just run whatever is creating that report, then pipe it to awk, and you're done. Pipes just direct output of the last command as the source of input for the next command.
â Falsenames
Jan 7 '15 at 17:06
add a comment |Â
up vote
1
down vote
Nice exercise here. I dumped the data in a file called "data" because I am very imaginative.
Well, you asked for it in bash... here it is in pure bash.
cat data | while read date i; do printf "%-10s " $date; for x in $(seq 1 $i); do echo -n "="; done; echo; done
awk is a better option.
awk ' s=" ";while ($2-->0) s=s"=";printf "%-10s %sn",$1,s ' data
Can you pipe the data through awk instead of using a file?
â Natim
Jan 7 '15 at 8:52
Yes, it's the same thing either way. Just add a "cat data |" at the beginning like I had for the bash bits, or a "<data" at the end. Or you can even just have the awk part without a file specified, paste in the data and hit ctrl-D at the end. Specifying the file just treats that file as stdin, and I didn't want to keep copying and pasting the datafile because I'm lazy.
â Falsenames
Jan 7 '15 at 16:47
1
Actually, I just reread the question while linking this to a coworker... you said you had "output", not a data file. So you can just run whatever is creating that report, then pipe it to awk, and you're done. Pipes just direct output of the last command as the source of input for the next command.
â Falsenames
Jan 7 '15 at 17:06
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Nice exercise here. I dumped the data in a file called "data" because I am very imaginative.
Well, you asked for it in bash... here it is in pure bash.
cat data | while read date i; do printf "%-10s " $date; for x in $(seq 1 $i); do echo -n "="; done; echo; done
awk is a better option.
awk ' s=" ";while ($2-->0) s=s"=";printf "%-10s %sn",$1,s ' data
Nice exercise here. I dumped the data in a file called "data" because I am very imaginative.
Well, you asked for it in bash... here it is in pure bash.
cat data | while read date i; do printf "%-10s " $date; for x in $(seq 1 $i); do echo -n "="; done; echo; done
awk is a better option.
awk ' s=" ";while ($2-->0) s=s"=";printf "%-10s %sn",$1,s ' data
answered Jan 7 '15 at 1:05
Falsenames
63748
63748
Can you pipe the data through awk instead of using a file?
â Natim
Jan 7 '15 at 8:52
Yes, it's the same thing either way. Just add a "cat data |" at the beginning like I had for the bash bits, or a "<data" at the end. Or you can even just have the awk part without a file specified, paste in the data and hit ctrl-D at the end. Specifying the file just treats that file as stdin, and I didn't want to keep copying and pasting the datafile because I'm lazy.
â Falsenames
Jan 7 '15 at 16:47
1
Actually, I just reread the question while linking this to a coworker... you said you had "output", not a data file. So you can just run whatever is creating that report, then pipe it to awk, and you're done. Pipes just direct output of the last command as the source of input for the next command.
â Falsenames
Jan 7 '15 at 17:06
add a comment |Â
Can you pipe the data through awk instead of using a file?
â Natim
Jan 7 '15 at 8:52
Yes, it's the same thing either way. Just add a "cat data |" at the beginning like I had for the bash bits, or a "<data" at the end. Or you can even just have the awk part without a file specified, paste in the data and hit ctrl-D at the end. Specifying the file just treats that file as stdin, and I didn't want to keep copying and pasting the datafile because I'm lazy.
â Falsenames
Jan 7 '15 at 16:47
1
Actually, I just reread the question while linking this to a coworker... you said you had "output", not a data file. So you can just run whatever is creating that report, then pipe it to awk, and you're done. Pipes just direct output of the last command as the source of input for the next command.
â Falsenames
Jan 7 '15 at 17:06
Can you pipe the data through awk instead of using a file?
â Natim
Jan 7 '15 at 8:52
Can you pipe the data through awk instead of using a file?
â Natim
Jan 7 '15 at 8:52
Yes, it's the same thing either way. Just add a "cat data |" at the beginning like I had for the bash bits, or a "<data" at the end. Or you can even just have the awk part without a file specified, paste in the data and hit ctrl-D at the end. Specifying the file just treats that file as stdin, and I didn't want to keep copying and pasting the datafile because I'm lazy.
â Falsenames
Jan 7 '15 at 16:47
Yes, it's the same thing either way. Just add a "cat data |" at the beginning like I had for the bash bits, or a "<data" at the end. Or you can even just have the awk part without a file specified, paste in the data and hit ctrl-D at the end. Specifying the file just treats that file as stdin, and I didn't want to keep copying and pasting the datafile because I'm lazy.
â Falsenames
Jan 7 '15 at 16:47
1
1
Actually, I just reread the question while linking this to a coworker... you said you had "output", not a data file. So you can just run whatever is creating that report, then pipe it to awk, and you're done. Pipes just direct output of the last command as the source of input for the next command.
â Falsenames
Jan 7 '15 at 17:06
Actually, I just reread the question while linking this to a coworker... you said you had "output", not a data file. So you can just run whatever is creating that report, then pipe it to awk, and you're done. Pipes just direct output of the last command as the source of input for the next command.
â Falsenames
Jan 7 '15 at 17:06
add a comment |Â
up vote
0
down vote
Try this:
while read value count; do
printf '%s:t%sn' "$value" "$(printf "%$counts" | tr ' ' '=')"
done <path/to/my-output
The only tricky part is the construction of the bar. I do it here by delegating to printf
and tr
like this SO answer.
As a bonus, it's POSIX-sh
-compliant.
References:
- https://stackoverflow.com/questions/5349718/how-can-i-repeat-a-character-in-bash/5349796#5349796
- https://www.unix.com/man-page/posix/1P/printf/
- https://www.unix.com/man-page/posix/1P/tr/
add a comment |Â
up vote
0
down vote
Try this:
while read value count; do
printf '%s:t%sn' "$value" "$(printf "%$counts" | tr ' ' '=')"
done <path/to/my-output
The only tricky part is the construction of the bar. I do it here by delegating to printf
and tr
like this SO answer.
As a bonus, it's POSIX-sh
-compliant.
References:
- https://stackoverflow.com/questions/5349718/how-can-i-repeat-a-character-in-bash/5349796#5349796
- https://www.unix.com/man-page/posix/1P/printf/
- https://www.unix.com/man-page/posix/1P/tr/
add a comment |Â
up vote
0
down vote
up vote
0
down vote
Try this:
while read value count; do
printf '%s:t%sn' "$value" "$(printf "%$counts" | tr ' ' '=')"
done <path/to/my-output
The only tricky part is the construction of the bar. I do it here by delegating to printf
and tr
like this SO answer.
As a bonus, it's POSIX-sh
-compliant.
References:
- https://stackoverflow.com/questions/5349718/how-can-i-repeat-a-character-in-bash/5349796#5349796
- https://www.unix.com/man-page/posix/1P/printf/
- https://www.unix.com/man-page/posix/1P/tr/
Try this:
while read value count; do
printf '%s:t%sn' "$value" "$(printf "%$counts" | tr ' ' '=')"
done <path/to/my-output
The only tricky part is the construction of the bar. I do it here by delegating to printf
and tr
like this SO answer.
As a bonus, it's POSIX-sh
-compliant.
References:
- https://stackoverflow.com/questions/5349718/how-can-i-repeat-a-character-in-bash/5349796#5349796
- https://www.unix.com/man-page/posix/1P/printf/
- https://www.unix.com/man-page/posix/1P/tr/
edited Jun 6 at 16:51
answered Jun 6 at 16:29
rubicks
1516
1516
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f177777%2fdrawing-a-histogram-from-a-bash-command-output%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
stackoverflow.com/questions/6949332/â¦
â ceejayoz
Jan 6 '15 at 16:52