बाश में $ # का क्या मतलब है?


26

मेरे पास एक फ़ाइल है जिसका नाम उदाहरण है:

echo "hello world"
echo ${1}

और जब मैं इस स्क्रिप्ट का उपयोग करता हूं:

./instance solfish

मुझे यह आउटपुट मिलता है:

hello world
solfish

लेकिन जब मैं दौड़ता हूं:

echo $# 

इसे कहते हैं "0"। क्यूं कर? मुझे समझ में नहीं आता कि क्या $#मतलब है।

कृपया इसे समझाएं।


10
तुम क्यों भागते हो $#? आपकी क्या प्राप्त करने की इच्छा है? आपको यह आज्ञा कहां से मिली। यह बिल्कुल भी प्रासंगिक नहीं है।
पायलट 6

7
@ Pilot6 इस मामले में वह एक चर का अर्थ पूछता है, यह मामला विशिष्ट नहीं है इसलिए ऑप को उस जानकारी को देने की आवश्यकता क्यों होगी?
एडीडीबी

21
@ सल्फ़िश पायलट यह समझने की कोशिश कर रहा है कि आप क्या उम्मीद कर रहे थे। आपने कहा कि आप भागे echo $#और यह लौटा 0जो सामान्य है। आप इससे आश्चर्यचकित थे, लेकिन आप यह नहीं समझाते कि आप क्या उम्मीद कर रहे थे या आप क्यों आश्चर्यचकित थे। तो यह आपको बेहतर उत्तर देने में हमारी मदद करेगा यदि आपने समझाया कि आप क्या उम्मीद कर रहे थे। आपने जो सोचा था वो echo $#करेंगे। यदि आप भागते ./instance solfishऔर ./instanceसम्‍मिलित होते echo $#, तो वह प्रिंट होता 1और नहीं 0
टेराडॉन


1
जावा भी argc का उपयोग नहीं करता है।
जेकरोबब जूल

जवाबों:


66

$#में एक विशेष चर है bash, जो तर्कों की संख्या (स्थितिगत मापदंडों) तक फैलता है, अर्थात $1, $2 ...प्रश्न में स्क्रिप्ट के पास या तर्क के मामले में शेल सीधे शेल में पारित होने जैसे bash -c '...' ....

यह argcC के समान है ।


शायद यह स्पष्ट कर देगा:

$ bash -c 'echo $#'
0

$ bash -c 'echo $#' _ x
1

$ bash -c 'echo $#' _ x y
2

$ bash -c 'echo $#' _ x y z
3

ध्यान दें, bash -cयह 0 से शुरू होने के बाद कमांड के बाद तर्क लेता है ( $0तकनीकी रूप से, यह bashआपको सेट करने का एक तरीका है $0, न कि एक तर्क वास्तव में), इसलिए _यहां एक प्लेसहोल्डर के रूप में उपयोग किया जाता है; वास्तविक तर्क हैं x( $1), y( $2), और z( $3)।


इसी तरह, script.shयदि आपके पास आपकी स्क्रिप्ट में (मान लिया जाता है ):

#!/usr/bin/env bash
echo "$#"

फिर जब आप करते हैं:

./script.sh foo bar

स्क्रिप्ट 2 का उत्पादन करेगा; इसी तरह,

./script.sh foo

आउटपुट 1 होगा।


1
मुझे लगता है कि यह उत्तर भ्रामक है। $ # तर्कों की सरणी का अधिकतम सूचकांक है। यदि आप एक तर्क देते हैं, जो $ 0 पर उपलब्ध होगा, और $ # का मूल्य होगा 0. यदि आप दो तर्क देते हैं, तो वे $ 0 और $ 1 में होंगे, और $ # का मान 1 होगा
JakeRobb

1
इसके अलावा, जब आप उपयोग करते हैं bash -c, तो व्यवहार अलग होता है यदि आप एक निष्पादन योग्य शेल स्क्रिप्ट चलाते हैं, क्योंकि बाद के मामले में सूचकांक 0 के साथ तर्क शेल कमांड है जो इसे लागू करने के लिए उपयोग किया जाता है। जैसे, मुझे लगता है कि इस उत्तर को ठीक करने का तरीका इसे स्क्रिप्ट को निष्पादित करने के लिए फ़ाइलों के रूप में उपयोग करने के बजाय बदलना है bash -c, क्योंकि यह पूछने वाला कैसे कर रहा था।
जेकरोबब जूल

1
@JakeRobb नंबर एक स्क्रिप्ट के लिए, $0स्क्रिप्ट ही होगी; तर्क होंगे $1, $2, $3...bash -cव्यवहार भिन्न है क्योंकि यह गैर-संवादात्मक उपयोग के लिए है और कमांड के बाद के तर्क शुरू होंगे $0, मैंने स्पष्ट रूप से इस विश्वास का उल्लेख किया है।
हेमायल

5
@JakeRobb आपने मुझे मिस किया है। यदि आप एक तर्क देते हैं, तो यह $ 0 पर उपलब्ध होगा, और $ # का मान 0 होगा - यह सादा गलत है।
हेमायल

2
यदि आप एक पूरा कार्यक्रम डालते हैं, जो यह देखता है कि यह args में है bash -c, तो आपको bash0 वें arg के लिए कुछ सार्थक नाम भरना चाहिए। bash -c 'echo "$@"' foo barकेवल प्रिंट bar, क्योंकि हमेशा की तरह "$@"शामिल नहीं है $0bash -c"$ 0 आर्ग में से एक बना" नहीं है, यह केवल आप सेट "$ 0" उसी तरह आप जब साथ एक कार्यक्रम चलाने के लिए अनुमति देता है सिस्टम कॉल या 0 आर्ग अधिभावी के किसी भी खोल रास्ता। कभी भी "अर्गल्स में से एक" नहीं माना जाना चाहिए। execve$0
पीटर कॉर्डेस

17

echo $# आपकी स्क्रिप्ट के स्थितीय मापदंडों की संख्या को आउटपुट करता है।

आपके पास कोई नहीं है, इसलिए यह 0 आउटपुट करता है।

echo $# स्क्रिप्ट के अंदर उपयोगी है, एक अलग कमांड के रूप में नहीं।

यदि आप कुछ मापदंडों के साथ एक स्क्रिप्ट चलाते हैं जैसे

./instance par1 par2

echo $#स्क्रिप्ट इच्छा उत्पादन 2 में रखा।


6
ओपी के उदाहरण के लिए: यदि आप echo $#अपनी स्क्रिप्ट में लाइन जोड़ते हैं और फिर से चलाने के लिए ./instance solfishआपको एक अतिरिक्त आउटपुट लाइन मिलनी चाहिए 1क्योंकि आपने 1 पैरामीटर प्रदान किया है
derHugo

14

$#एक पैरामीटर पारित करने के लिए आमतौर पर बैश स्क्रिप्ट में उपयोग किया जाता है। आम तौर पर आप अपनी स्क्रिप्ट की शुरुआत में एक पैरामीटर की जांच करते हैं।

उदाहरण के लिए यहाँ एक स्क्रिप्ट का एक टुकड़ा है जो मैं आज काम कर रहा था:

if [[ $# -ne 1 ]]; then
    echo 'One argument required for file name, e.g. "Backup-2017-07-25"'
    echo '.tar will automatically be added as a file extension'
    exit 1
fi

$#किसी स्क्रिप्ट में दिए गए मापदंडों की संख्या को संक्षेप में प्रस्तुत करने के लिए। आपके मामले में आपने कोई पैरामीटर नहीं दिया है और रिपोर्ट किया गया परिणाम है 0


#बाश में अन्य उपयोग

#अक्सर घटनाओं की संख्या या एक चर की लंबाई गिनती करने के लिए पार्टी में प्रयोग किया जाता है।

एक स्ट्रिंग की लंबाई खोजने के लिए:

myvar="some string"; echo ${#myvar}

रिटर्न: 11

सरणी तत्वों की संख्या ज्ञात करने के लिए:

myArr=(A B C); echo ${#myArr[@]}

रिटर्न: 3

पहले सरणी तत्व की लंबाई जानने के लिए:

myArr=(A B C); echo ${#myArr[0]}

रिटर्न: 1(की लंबाई A, 0 पहला तत्व है क्योंकि सरणियाँ शून्य-आधारित सूचकांकों / सदस्यता का उपयोग करती हैं)।


$# -ne 1? क्यों $# -le 0या समकक्ष नहीं ?
पैट्रिक ट्रेंटिन

@PatrickTrentin क्योंकि मैं नहीं चाहता कि वे दो या अधिक मापदंडों को पारित करें। जैसा कि कैप्टन ने "रेड अक्टूबर" में कहा था: "जस्ट वन"।
विनयुनुच्स 2 यूनिक्स 12

तब: त्रुटि संदेश में "बिल्कुल एक तर्क की आवश्यकता है ..."
पैट्रिक ट्रेंटिन

@PatrickTrentin त्रुटि संदेश यह बताता है कि स्क्रिप्ट का उपयोग एक तर्क उपयोग के उदाहरण के साथ कैसे किया जाता है। इसके अलावा बैकअप स्क्रिप्ट को cron.daily द्वारा कॉल किया जाता है जो केवल एक बार किसी टेक सेवी द्वारा कॉन्फ़िगर किया गया है: askubuntu.com/questions/917562/…
WinEunuuchs2Unix

यह कैसे प्रासंगिक है मुझे नहीं पता होगा। वैसे भी, चीयर्स।
पैट्रिक ट्रेंटिन

10

$# तर्कों की संख्या है, लेकिन याद रखें कि यह एक फ़ंक्शन में भिन्न होगी।

$#स्क्रिप्ट, शेल या शेल फ़ंक्शन को पारित किए गए स्थितीय मापदंडों की संख्या है । ऐसा इसलिए है, क्योंकि शेल फ़ंक्शन चल रहा है, स्थिति संबंधी पैरामीटर अस्थायी रूप से फ़ंक्शन के तर्कों के साथ बदल दिए जाते हैं । इससे फ़ंक्शन अपने स्वयं के स्थितीय मापदंडों को स्वीकार करते हैं और उपयोग करते हैं।

यह स्क्रिप्ट हमेशा प्रिंट करती है 3, भले ही स्क्रिप्ट में कितने तर्क पास किए गए हों, क्योंकि "$#"फ़ंक्शन में फ़ंक्शन के fलिए दिए गए तर्कों की संख्या तक विस्तार होता है:

#!/bin/sh

f() {
    echo "$#"
}

f a b c

यह महत्वपूर्ण है क्योंकि इसका मतलब है कि इस तरह का कोड काम नहीं करता है जैसा कि आप उम्मीद कर सकते हैं, यदि आप परिचित नहीं हैं कि शेल के कार्यों में स्थितीय पैरामीटर कैसे काम करते हैं:

#!/bin/sh

check_args() { # doesn't work!
    if [ "$#" -ne 2 ]; then
        printf '%s: error: need 2 arguments, got %d\n' "$0" "$#" >&2
        exit 1
    fi
}

# Maybe check some other things...
check_args
# Do other stuff...

में check_args, $#फंक्शन में पास किए गए तर्कों की संख्या तक विस्तार होता है, जो उस स्क्रिप्ट में हमेशा 0 होता है।

यदि आप शेल फ़ंक्शन में ऐसी कार्यक्षमता चाहते हैं, तो आपको इसके बजाय कुछ इस तरह लिखना होगा:

#!/bin/sh

check_args() { # works -- the caller must pass the number of arguments received
    if [ "$1" -ne 2 ]; then
        printf '%s: error: need 2 arguments, got %d\n' "$0" "$1" >&2
        exit 1
    fi
}

# Maybe check some other things...
check_args "$#"

यह काम करता है क्योंकि फ़ंक्शन के बाहर$# विस्तारित होता है और फ़ंक्शन के पास इसके स्थितीय मापदंडों में से एक के रूप में पारित किया जाता है । फ़ंक्शन के अंदर, उस स्क्रिप्ट का हिस्सा होने के बजाय शेल फ़ंक्शन को दिए गए पहले स्थितीय पैरामीटर को विस्तारित करता है, जिसका वह हिस्सा है।$1

इस प्रकार, जैसे $#, विशेष पैरामीटर $1, $2आदि, साथ ही $@और $*, फ़ंक्शन में दिए गए तर्कों से भी संबंधित होते हैं, जब वे फ़ंक्शन में विस्तारित होते हैं। हालांकि, $0करता नहीं क्यों मैं अभी भी इसका इस्तेमाल करने के लिए एक गुणवत्ता त्रुटि संदेश का उत्पादन करने में सक्षम था समारोह है, जो के नाम करने के लिए बदल जाते हैं।

$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3

इसी तरह, यदि आप एक फ़ंक्शन को दूसरे के अंदर परिभाषित करते हैं, तो आप उस अंतरतम पैरामीटर के साथ काम कर रहे हैं जो अंतरतम फ़ंक्शन को दिया जाता है जिसमें विस्तार किया जाता है:

#!/bin/sh

outer() {
    inner() {
        printf 'inner() got %d arguments\n' "$#"
    }

    printf 'outer() got %d arguments\n' "$#"
    inner x y z
}

printf 'script got %d arguments\n' "$#"
outer p q

मैंने इस स्क्रिप्ट को बुलाया nestedऔर (चलाने के बाद chmod +x nested) मैंने इसे चलाया:

$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments

हाँ मैं जानता हूँ। "" तर्क "एक बहुवचन बग है।

स्थितिगत मापदंडों को भी बदला जा सकता है।

यदि आप एक स्क्रिप्ट लिख रहे हैं, तो एक फ़ंक्शन के बाहर स्थित स्थिति के पैरामीटर स्क्रिप्ट के पास दिए गए कमांड-लाइन तर्क होंगे जब तक कि आपने उन्हें नहीं बदला है

उन्हें बदलने का एक सामान्य तरीका shiftबिलिन के साथ है , जो प्रत्येक स्थितीय पैरामीटर को एक से बाईं ओर बदलता है, पहले को छोड़ता है और $#1 से घटता है:

#!/bin/sh

while [ "$#"  -ne 0 ]; do
    printf '%d argument(s) remaining.\nGot "%s".\n\n' "$#" "$1"
    shift
done
$ ./do-shift foo bar baz      # I named the script do-shift.
3 argument(s) remaining.
Got "foo".

2 argument(s) remaining.
Got "bar".

1 argument(s) remaining.
Got "baz".

उन्हें setबिलिन के साथ भी बदला जा सकता है :

#!/bin/sh

printf '%d args: %s\n' "$#" "$*"
set foo bar baz
printf '%d args: %s\n' "$#" "$*"
$ ./set-args a b c d e      # I named the script set-args.
5 args: a b c d e
3 args: foo bar baz

1
शिक्षाप्रद उत्तर के लिए कुडोस जो पूछा गया था उससे परे चला गया लेकिन मूल प्रश्नकर्ता और मेरे जैसे अन्य लोगों के सीखने के इरादों का जवाब दिया!
रिकार्डो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.