बाश में दो चरों को घटाना


220

मेरे पास दो निर्देशिकाओं के बीच फ़ाइलों की गणना को घटाने के लिए नीचे दी गई स्क्रिप्ट है, लेकिन COUNT=अभिव्यक्ति काम नहीं करती है। सही सिंटैक्स क्या है?

#!/usr/bin/env bash

FIRSTV=`ls -1 | wc -l`
cd ..
SECONDV=`ls -1 | wc -l`
COUNT=expr $FIRSTV-$SECONDV  ## -> gives 'command not found' error
echo $COUNT

जवाबों:


224

आपको माइनस साइन के चारों ओर थोड़े अतिरिक्त व्हाट्सएप की आवश्यकता है, और बैकटिक्स:

COUNT=`expr $FIRSTV - $SECONDV`

निकास स्थिति से अवगत रहें:

बाहर निकलने की स्थिति 0 है यदि एक्सप्रेशन न तो शून्य है और न ही 0, 1 यदि एक्सप्रेशन शून्य या 0 है

सेट-ई के संयोजन में एक बैश स्क्रिप्ट में अभिव्यक्ति का उपयोग करते समय इसे ध्यान में रखें जो एक गैर-शून्य स्थिति के साथ एक कमांड से बाहर निकलने पर तुरंत बाहर निकल जाएगा।


2
यह उत्तर पॉज़िक्स shशेल में भी काम करता है । पोर्टेबिलिटी के लिए, आप इस उत्तर का उपयोग करना चाह सकते हैं।
dinkelk

यह ध्यान देने योग्य है कि शेलचेक के अनुसार, expr एक ऐसा कोड है, जिसके कारण यह पुरातन और उपयोग करने में मुश्किल है: github.com/koalaman/shellcheck/wiki/SC2003
जॉन हैमिलिंक

369

बाहरी प्रोग्राम का उपयोग करने के बजाय इस बैश सिंटैक्स को आज़माएं expr:

count=$((FIRSTV-SECONDV))

BTW, उपयोग करने exprका सही सिंटैक्स है:

count=$(expr $FIRSTV - $SECONDV)

लेकिन ध्यान रखें exprकि मैं ऊपर दिए गए आंतरिक बैश सिंटैक्स की तुलना में धीमा होने जा रहा हूं।


4
यह फ़ॉर्म expr बाहरी प्रोग्राम का उपयोग करने की तुलना में तेज है।
एनएस

यह बैकटिक्स के बिना काम करता है, लेकिन क्या मुझे पता है कि क्यों? Aswe.r के लिए +1
अमल मुरली

2
धन्यवाद। बैकटिक पुराना शेल सिंटैक्स है। BASH $(command)कमांड प्रतिस्थापन के लिए नए सिंटैक्स का समर्थन करता है । चूँकि BASH इसमें अंकगणितीय संक्रियाओं का समर्थन $(( ... ))करता है, इसलिए बाहरी उपयोगिता का उपयोग न करना बेहतर हैexpr
Aubhava

1
मैं कभी भी "$" के बिना चर का संदर्भ नहीं दे सकता, बहुत दिलचस्प है। यह सिर्फ FYI करें Ubuntu 12,14 पर काम करता है।
MadHatter

1
@ AlikElzin-kilaka: बैश $(( ... ))में अंकगणितीय अभिव्यक्तियों के मूल्यांकन के लिए उपयोग किया जाता है।
शुभ

30

आप उपयोग कर सकते हैं:

((count = FIRSTV - SECONDV))

निम्नलिखित प्रतिलेख के अनुसार एक अलग प्रक्रिया को लागू करने से बचने के लिए:

pax:~$ FIRSTV=7
pax:~$ SECONDV=2
pax:~$ ((count = FIRSTV - SECONDV))
pax:~$ echo $count
5

12

श्वेत स्थान महत्वपूर्ण है, exprअपने ऑपरेटरों और ऑपरेटरों से अलग-अलग तर्क के रूप में अपेक्षा करता है। आपको आउटपुट भी कैप्चर करना होगा। ऐशे ही:

COUNT=$(expr $FIRSTV - $SECONDV)

लेकिन यह बिल्टिन अंकगणितीय विस्तार का उपयोग करने के लिए अधिक सामान्य है:

COUNT=$((FIRSTV - SECONDV))

12

इस तरह मैं हमेशा बैश में गणित करता हूं:

count=$(echo "$FIRSTV - $SECONDV"|bc)
echo $count

5
यदि आप फ्लोटिंग पॉइंट नंबरों के साथ काम कर रहे हैं तो यह केवल आवश्यक है।
ग्लेन जैकमैन

2
मुझे लगता है कि, लेकिन मैं एक |bcबार या दो बार याद करने की तुलना में एक प्रकार के आदेश के साथ उन मामलों को पकड़ने की आदत बनाना चाहते हैं । जैसा कि वे कहते हैं, विभिन्न लोगों के लिए अलग स्ट्रोक।
प्योरफेरेट

5

सरल पूर्णांक अंकगणित के लिए, आप बिलिन लेट कमांड का भी उपयोग कर सकते हैं ।

 ONE=1
 TWO=2
 let "THREE = $ONE + $TWO"
 echo $THREE
    3

अधिक जानकारी के लिए let, यहां देखें


@ other.anon.coward आपका लिंक मेरा +1 से बेहतर है। (... और चोरी लिंक)
शॉन चिन

इस काम को करने में बहुत परेशानी हुई। अंत में यह काम किया - let "sanity_check_duration=sanity_check_duration_end_time_delay_sec - sanity_check_duration_start_time_delay_sec"(चर से डॉलर के चिह्न को हटाते हुए)
संदीपन नाथ

2

वैकल्पिक रूप से सुझाए गए 3 तरीकों से आप यह कोशिश कर सकते हैं letकि चर पर अंकगणितीय ऑपरेशन किए जाएं:

let COUNT=$FIRSTV-$SECONDV

या

let COUNT=FIRSTV-SECONDV


0

अजगर का उपयोग करें:

#!/bin/bash
# home/victoria/test.sh

START=$(date +"%s")                                     ## seconds since Epoch
for i in $(seq 1 10)
do
  sleep 1.5
  END=$(date +"%s")                                     ## integer
  TIME=$((END - START))                                 ## integer
  AVG_TIME=$(python -c "print(float($TIME/$i))")        ## int to float
  printf 'i: %i | elapsed time: %0.1f sec | avg. time: %0.3f\n' $i $TIME $AVG_TIME
  ((i++))                                               ## increment $i
done

उत्पादन

$ ./test.sh 
i: 1 | elapsed time: 1.0 sec | avg. time: 1.000
i: 2 | elapsed time: 3.0 sec | avg. time: 1.500
i: 3 | elapsed time: 5.0 sec | avg. time: 1.667
i: 4 | elapsed time: 6.0 sec | avg. time: 1.500
i: 5 | elapsed time: 8.0 sec | avg. time: 1.600
i: 6 | elapsed time: 9.0 sec | avg. time: 1.500
i: 7 | elapsed time: 11.0 sec | avg. time: 1.571
i: 8 | elapsed time: 12.0 sec | avg. time: 1.500
i: 9 | elapsed time: 14.0 sec | avg. time: 1.556
i: 10 | elapsed time: 15.0 sec | avg. time: 1.500
$
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.