बैश कमांड आउटपुट से हिस्टोग्राम खींचना


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 =
...

क्या आप जानते हैं कि अगर कोई बैश कमांड है जो मुझे ऐसा करने देगा?


1
bashplotlib एक अच्छा समाधान है
माइकल Mior

यह वास्तव में स्व-निहित जवाबों के बजाय लिंक प्रदान करने के जोखिमों में से एक है। यदि हटाए गए SO उत्तर उपयोगी है, तो कृपया इसे यहां एक उत्तर के रूप में पोस्ट करें।
जेफ स्कालर

जवाबों:


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)'यह वास्तव में बहुत अच्छा लग रहा है :) धन्यवाद
नटिम

12

इन perl:

perl -pe 's/ (\d+)$/"="x$1/e' file
  • eअभिव्यक्ति का मूल्यांकन करने का कारण बनता है, इसलिए मैं (द्वारा मिलान की गई संख्या ) =के मूल्य का उपयोग करके दोहराया जाता हूं ।$1(\d+)
  • आप छोटी लाइनों को प्राप्त करने के "="x($1\/3)बजाय कर सकते हैं "="x$1। ( /जब हम एक प्रतिस्थापन आदेश के बीच में हैं तो बच गए हैं।)

इन bash( इस एसओ उत्तर से प्रेरित ):

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
एक खोल समाधान भी दिखाने के लिए ब्रावो। आपका पर्ल समाधान भी बहुत साफ है।
चूजों

@mikeserv अद्भुत! मैं हमेशा भूल जाता हूं %*sभले ही यह printfसी-प्रोग्रामिंग में सीखी गई पहली- संबंधित चाल थी।
मुरु

printf(sed) | trसंस्करण नहीं है यहाँ जहाँ तक मैं बता सकता है काम करता है।
नटिम

@ नैतीम यहाँ कहाँ हो रहा है?
मुरु

तर्क लंबाई में @mikeserv सीमाएं शायद?
मूरू

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");}'

ऊपर दी गई छोटी स्क्रिप्ट डेटा मानती है कि एक फाइल कल्पनाशील रूप से "डेटा" नाम की है।

मैं "इसे सीड और सॉर्ट के माध्यम से चलाता हूं" लाइन से बहुत खुश नहीं हूं - यह अनावश्यक होगा यदि आपके महीने और दिन के महीने में हमेशा 2 अंक होते हैं, लेकिन यह जीवन है।

इसके अलावा, एक ऐतिहासिक नोट के रूप में, पारंपरिक यूनिक्स एक कमांड लाइन साजिश रचने वाली उपयोगिता के साथ आते थे जो काफी बदसूरत ASCII रेखांकन और भूखंड कर सकते थे। मुझे नाम याद नहीं है, लेकिन ऐसा लगता है कि जीएनयू के प्लॉटुटिल्स पुरानी पारंपरिक उपयोगिता की जगह लेते हैं।


ऐसा नहीं होना चाहिए if ($1 in count) ...?
मुरु

1
@ मरमू - या तो काम करने लगता है। हालाँकि, मुझे "और" खंड में एक टाइपो मिला। धन्यवाद।
ब्रूस एडगर

1

यहाँ अच्छा व्यायाम। मैंने डेटा को "डेटा" नामक फ़ाइल में डंप किया क्योंकि मैं बहुत कल्पनाशील हूं।

ठीक है, आपने इसे बाश में कहा ... यहाँ यह शुद्ध बैश में है।

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

जाग एक बेहतर विकल्प है।

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

क्या आप फ़ाइल का उपयोग करने के बजाय awk के माध्यम से डेटा को पाइप कर सकते हैं?
नटिम

हां, यह एक ही बात है। बस एक "बिल्ली डेटा जोड़ें।" शुरुआत में जैसे मेरे पास बैश बिट्स के लिए था, या अंत में एक "<डेटा" था। या आप केवल एक निर्दिष्ट फ़ाइल के बिना awk हिस्सा भी रख सकते हैं, डेटा में पेस्ट करें और अंत में ctrl-D मारा। फ़ाइल को निर्दिष्ट करना बस उस फ़ाइल को स्टडिन के रूप में मानता है, और मैं डेटाफ़ाइल को कॉपी और पेस्ट करना नहीं चाहता था क्योंकि मैं आलसी हूं।
फर्ल्सनमेंस

1
वास्तव में, मैं सिर्फ इस सवाल को एक सहकर्मी से जोड़ते हुए फिर से सवाल करता हूं ... आपने कहा था कि आपके पास "आउटपुट" था, डेटा फ़ाइल नहीं। तो आप बस जो कुछ भी बना रहे हैं उस रिपोर्ट को चला सकते हैं, फिर इसे जागने के लिए पाइप करें, और आप कर रहे हैं। अगले कमांड के इनपुट के स्रोत के रूप में पाइप्स अंतिम कमांड का सिर्फ सीधा आउटपुट है।
फालसेनमेंस

0

इसे इस्तेमाल करे:

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

एकमात्र मुश्किल हिस्सा बार का निर्माण है। मैं करने के लिए सौंपने से यहाँ यह करने के printfऔर trकी तरह इस अतः जवाब

एक बोनस के रूप में, यह POSIX-sh

संदर्भ:

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.