shell - शैल कमांड प्रति पूर्णांक, एक पंक्ति के लिए?




(20)

मैं एक कमांड की तलाश में हूं जो पाठ की इनपुट एकाधिक पंक्तियों के रूप में स्वीकार करेगा, प्रत्येक पंक्ति में एक पूर्णांक होता है, और इन पूर्णांकों का योग आउटपुट करता है।

कुछ पृष्ठभूमि के रूप में, मेरे पास एक लॉग फ़ाइल है जिसमें समय माप शामिल है, इसलिए प्रासंगिक लाइनों के लिए grepping के माध्यम से, और कुछ sed reformatting मैं उस फ़ाइल में सभी समय सूचीबद्ध कर सकते हैं। हालांकि मैं कुल मिलाकर काम करना चाहता हूं, और मेरा दिमाग किसी भी कमांड के रूप में खाली हो गया है, मैं अंतिम इनपुट करने के लिए इस मध्यवर्ती आउटपुट को पाइप कर सकता हूं। मैंने हमेशा अतीत में expr का उपयोग किया है, लेकिन जब तक यह RPN mode में नहीं चलता है, मुझे नहीं लगता कि यह इस से निपटने जा रहा है (और फिर भी यह मुश्किल होगा)।

मैं क्या खो रहा हूँ? यह देखते हुए कि संभवतः इसे प्राप्त करने के कई तरीके हैं, मुझे काम करने वाले किसी भी दृष्टिकोण को पढ़ने (और ऊपर upvote ) में खुशी होगी, भले ही किसी और ने पहले से ही एक अलग समाधान पोस्ट किया हो जो नौकरी करता है।

संबंधित प्रश्न: यूनिक्स पर आउटपुट के कॉलम के योग की गणना करने के लिए सबसे कमांड कमांड? (क्रेडिट @Andrew )

अपडेट करें : वाह, जैसा कि उम्मीद है कि यहां कुछ अच्छे जवाब दिए गए हैं। ऐसा लगता है कि मुझे निश्चित रूप से command-line tool के रूप में command-line tool गहन निरीक्षण करना होगा!


अजीब बिट इसे करना चाहिए?

awk '{s+=$1} END {print s}' mydatafile

नोट: यदि आप 2 ^ 31 (2147483647) से अधिक कुछ जोड़ने जा रहे हैं तो अजीब के कुछ संस्करणों में कुछ अजीब व्यवहार हैं। अधिक पृष्ठभूमि के लिए टिप्पणियां देखें। print बजाय printf का उपयोग करना एक सुझाव है:

awk '{s+=$1} END {printf "%.0f", s}' mydatafile

आप num-utils का उपयोग कर सकते हैं, हालांकि यह आपके लिए आवश्यक चीज़ों के लिए अधिक हो सकता है। यह शैल में संख्याओं में हेरफेर करने के लिए कार्यक्रमों का एक सेट है, और पाठ्यक्रम सहित, कई निफ्टी चीजें कर सकते हैं। यह बहुत पुराना है, लेकिन वे अभी भी काम करते हैं और यदि आप कुछ और करने की ज़रूरत है तो उपयोगी हो सकते हैं।

http://suso.suso.org/programs/num-utils/


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


निम्नलिखित कार्य करना चाहिए (माना जाता है कि आपका नंबर प्रत्येक पंक्ति पर दूसरा क्षेत्र है)।

awk 'BEGIN {sum=0} \
 {sum=sum + $2} \
END {print "tot:", sum}' Yourinputfile.txt

पायथन में एक लाइनर संस्करण:

$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"

पेस्ट आम तौर पर कई फाइलों की रेखाओं को विलय करता है, लेकिन इसका उपयोग फ़ाइल की अलग-अलग पंक्तियों को एक पंक्ति में बदलने के लिए भी किया जा सकता है। डेलीमीटर फ़्लैग आपको एक्स + एक्स टाइप समीकरण को बीसी में पास करने की अनुमति देता है।

paste -s -d+ infile | bc

वैकल्पिक रूप से, जब stdin से पाइपिंग,

<commands> | paste -s -d+ - | bc

मुझे एहसास है कि यह एक पुराना सवाल है, लेकिन मुझे यह समाधान साझा करने के लिए पर्याप्त समाधान पसंद है।

% cat > numbers.txt
1 
2 
3 
4 
5
^D
% cat numbers.txt | perl -lpe '$c+=$_}{$_=$c'
15

यदि रुचि है, तो मैं समझाऊंगा कि यह कैसे काम करता है।


मुझे लगता है कि एडब्ल्यूके वह है जो आप खोज रहे हैं: awk '{sum+=$1}END{print sum}'

आप या तो मानक इनपुट के माध्यम से संख्याओं को पास करके या पैरामीटर के रूप में संख्या वाले फ़ाइल को पास करके इस आदेश का उपयोग कर सकते हैं।


मेरे पंद्रह सेंट:

$ cat file.txt | xargs  | sed -e 's/\ /+/g' | bc

उदाहरण:

$ cat text
1
2
3
3
4
5
6
78
9
0
1
2
3
4
576
7
4444
$ cat text | xargs  | sed -e 's/\ /+/g' | bc 
5148

मैं आमतौर पर अनुमोदित समाधान पर एक बड़ी चेतावनी डालता हूं:

awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!

ऐसा इसलिए है क्योंकि इस रूप में अजीब 32 बिट हस्ताक्षरित पूर्णांक प्रतिनिधित्व का उपयोग करता है: यह 2147483647 (यानी, 2 ^ 31) से अधिक की रकम के लिए बह जाएगा।

एक और सामान्य उत्तर (संक्षेप में पूर्णांक के लिए) होगा:

awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD

पीएस मुझे पहले जवाब पर टिप्पणी करना पसंद होता, लेकिन मेरे पास पर्याप्त प्रतिष्ठा नहीं है ..


यदि आप आरामदायक महसूस करते हैं, तो आप इसे अजगर में कर सकते हैं:

परीक्षण नहीं किया गया, बस टाइप किया गया:

out = open("filename").read();
lines = out.split('\n')
ints = map(int, lines)
s = sum(ints)
print s

सेबेस्टियन ने एक लाइनर स्क्रिप्ट की ओर इशारा किया:

cat filename | python -c"from fileinput import input; print sum(map(int, input()))"

रीयल-टाइम संक्षेप में आपको कुछ संख्या-क्रंचिंग कार्य की प्रगति की निगरानी करने दें।

$ cat numbers.txt 
1
2
3
4
5
6
7
8
9
10

$ cat numbers.txt | while read new; do total=$(($total + $new)); echo $total; done
1
3
6
10
15
21
28
36
45
55

(इस मामले में $total शून्य सेट करने की कोई आवश्यकता नहीं है। न तो आप खत्म होने के बाद $ कुल तक पहुंच सकते हैं।)


रैकेट में एक लाइनर:

racket -e '(define (g) (define i (read)) (if (eof-object? i) empty (cons i (g)))) (foldr + 0 (g))' < numlist.txt

वैकल्पिक शुद्ध पर्ल, काफी पठनीय, कोई पैकेज या विकल्प आवश्यक:

perl -e "map {$x += $_} <> and print $x" < infile.txt

शुद्ध बैश और एक लाइनर में :-)

$ cat numbers.txt
1
2
3
4
5
6
7
8
9
10


$ I=0; for N in $(cat numbers.txt); do I=$(($I + $N)); done; echo $I
55

सादा एक लाइनर बाश

$ cat > /tmp/test
1 
2 
3 
4 
5
^D

$ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))

सी (सरलीकृत नहीं)

seq 1 10 | tcc -run <(cat << EOF
#include <stdio.h>
int main(int argc, char** argv) {
    int sum = 0;
    int i = 0;
    while(scanf("%d", &i) == 1) {
        sum = sum + i;
    }
    printf("%d\n", sum);
    return 0;
}
EOF)

jq साथ:

seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'

dc -f infile -e '[+z1<r]srz1<rp'

ध्यान दें कि शून्य चिह्न के साथ prefixed नकारात्मक संख्या dc लिए अनुवाद किया जाना चाहिए, क्योंकि यह इसके लिए उपसर्ग के बजाय _ उपसर्ग का उपयोग करता है। उदाहरण के लिए, tr '-' '_' | dc -f- -e '...' माध्यम से tr '-' '_' | dc -f- -e '...'

संपादित करें: चूंकि इस जवाब को "अस्पष्टता के लिए" इतने सारे वोट मिले हैं, यहां एक विस्तृत स्पष्टीकरण दिया गया है:

अभिव्यक्ति [+z1<r]srz1<rp निम्न कार्य करता है :

[   interpret everything to the next ] as a string
  +   push two values off the stack, add them and push the result
  z   push the current stack depth
  1   push one
  <r  pop two values and execute register r if the original top-of-stack (1)
      is smaller
]   end of the string, will push the whole thing to the stack
sr  pop a value (the string above) and store it in register r
z   push the current stack depth again
1   push 1
<r  pop two values and execute register r if the original top-of-stack (1)
    is smaller
p   print the current top-of-stack

छद्म कोड के रूप में:

  1. "Add_top_of_stack" को परिभाषित करें:
    1. ढेर से दो शीर्ष मूल्यों को हटाएं और परिणाम वापस जोड़ें
    2. यदि स्टैक में दो या दो से अधिक मान हैं, तो "add_top_of_stack" को दोबारा चलाएं
  2. यदि स्टैक में दो या दो से अधिक मान हैं, तो "add_top_of_stack" चलाएं
  3. परिणाम प्रिंट करें, अब स्टैक में एकमात्र आइटम छोड़ा गया है

dc की सादगी और शक्ति को वास्तव में समझने के लिए, यहां एक काम करने वाली पायथन लिपि है जो dc से कुछ आदेश लागू करती है और उपरोक्त आदेश के पाइथन संस्करण को निष्पादित करती है:

### Implement some commands from dc
registers = {'r': None}
stack = []
def add():
    stack.append(stack.pop() + stack.pop())
def z():
    stack.append(len(stack))
def less(reg):
    if stack.pop() < stack.pop():
        registers[reg]()
def store(reg):
    registers[reg] = stack.pop()
def p():
    print stack[-1]

### Python version of the dc command above

# The equivalent to -f: read a file and push every line to the stack
import fileinput
for line in fileinput.input():
    stack.append(int(line.strip()))

def cmd():
    add()
    z()
    stack.append(1)
    less('r')

stack.append(cmd)
store('r')
z()
stack.append(1)
less('r')
p()

perl -lne '$x += $_; END { print $x; }' < infile.txt




shell