एक बैश शेल स्क्रिप्ट में सभी तर्कों का प्रचार करें


848

मैं एक बहुत ही सरल स्क्रिप्ट लिख रहा हूं जो दूसरी स्क्रिप्ट को कॉल करता है, और मुझे अपनी वर्तमान स्क्रिप्ट से उस स्क्रिप्ट को निष्पादित करने की आवश्यकता है जो मैं निष्पादित कर रहा हूं।

उदाहरण के लिए, मेरा स्क्रिप्ट नाम है foo.shऔर कॉलbar.sh

foo.sh:

bar $1 $2 $3 $4

प्रत्येक पैरामीटर को स्पष्ट रूप से निर्दिष्ट किए बिना मैं यह कैसे कर सकता हूं?



जवाबों:


1402

"$@"सादे के बजाय का उपयोग करें $@यदि आप वास्तव में चाहते हैं कि आपके पैरामीटर समान हों।

का निरीक्षण करें:

$ cat foo.sh
#!/bin/bash
baz.sh $@

$ cat bar.sh
#!/bin/bash
baz.sh "$@"

$ cat baz.sh
#!/bin/bash
echo Received: $1
echo Received: $2
echo Received: $3
echo Received: $4

$ ./foo.sh first second
Received: first
Received: second
Received:
Received:

$ ./foo.sh "one quoted arg"
Received: one
Received: quoted
Received: arg
Received:

$ ./bar.sh first second
Received: first
Received: second
Received:
Received:

$ ./bar.sh "one quoted arg"
Received: one quoted arg
Received:
Received:
Received:

7
यह उद्धृत / बच गए तारों के माध्यम से शुद्ध पास के लिए यह काम करता है: निरीक्षण करें: बिल्ली rsync_f.sh #! / Bin / bash echo "$ @" rsync "$ @" ./rsync_foo.sh-n "-n" bar me "bar2 bar me। bar2skipping डायरेक्टरी बार me क्या शेल स्क्रिप्ट का होना संभव है जो उद्धरण या बच गए तार के साथ वास्तविक मूल कमांड लाइन को पूरा कर सकता है?
मार्क एडिंगटन

3
झंडे पास करने के बारे में क्या? जैसे, './bar.sh-with-stuff'
नाथन लॉन्ग

4
मैं किसी को भी सुझाव देता हूं जो वर्ड स्प्लिटिंग के विषय को बेहतर ढंग से समझना चाहता है, इसके बारे में और अधिक पढ़ने के
रानी एल्बेग वेन

4
मेरा सुझाव है कि जब 'arg with spaces'तीन उदाहरणों के लिए भी शामिल हो तो आप क्या करें । मैं परिणामों से हैरान था; उम्मीद है कि आप उन्हें समझा सकते हैं।
माइकल शेपर

2
@MichaelScheper, किसी भी तरह, ./foo.sh "arg with spaces"और ./foo.sh 'arg with spaces'100% समान हैं, इसलिए मैं यह नहीं देखता कि दिए गए उदाहरणों में इसे जोड़ने का सुझाव किसी भी मदद का कैसे होगा।
चार्ल्स डफी

475

के लिए पार्टी और अन्य बॉर्न की तरह गोले:

java com.myserver.Program "$@"

13
@Amir: नहीं, csh के लिए नहीं । हर किसी की पवित्रता के लिए: स्क्रिप्ट csh नहीं । लेकिन मुझे लगता है कि शायद $argv:qकुछ csh वेरिएंट में काम करेगा।
क्रिस जॉन्सन

2
धन्यवाद! इच्छानुसार, यह स्क्रिप्ट द्वारा प्राप्त तर्कों का एक ही सेट पास करता है - एक बड़ा तर्क नहीं। दोहरे-उद्धरण आवश्यक हैं। यहां तक ​​कि काम करता है अगर उद्धृत तर्क के साथ रिक्त स्थान शामिल हैं।
एंडी थॉमस

24
संबंधित: यदि आपकी शेल स्क्रिप्ट जावा को चलाने के लिए एक आवरण के रूप में काम कर रही है, तो अंतिम पंक्ति बनाने पर विचार करें। exec java com.myserver.Program "$@"यह जावा में निष्पादित करने के लिए बैश करता है, बजाय इसके पूरा होने के लिए प्रतीक्षा करने के। तो, आप एक कम प्रोसेस स्लॉट का उपयोग कर रहे हैं। इसके अलावा, अगर अभिभावक प्रक्रिया (जो आपकी स्क्रिप्ट को चलाती है) इसे पीआईडी ​​के माध्यम से देख रही है, और यह उम्मीद कर रही है कि यह 'जावा' प्रक्रिया है, तो कुछ असामान्य चीजें टूट सकती हैं यदि आप एक निष्पादन नहीं करते हैं; क्रियान्वित होने से जावा को एक ही प्रकार की विरासत प्राप्त होती है।
greggo

7
@dragonxlwang: आप एक सरणी चर इस्तेमाल कर सकते हैं, यदि आपका खोल उन्हें समर्थन करता है (उदाहरण के लिए पार्टी , zsh , दूसरों, लेकिन मैदान नहीं Bourne- या POSIX-खोल): को बचाने आर्ग के साथ args=("$@")और एक अलग खोल "शब्द" के रूप में प्रत्येक तत्व का विस्तार ( जैसा "$@"के साथ) "${args[@]}"
क्रिस जॉन्सन

1
उपयोग करते समय ध्यान में रखने के लिए क्या कोई "गोचर" है "$@", जैसे कि यदि आप एक तर्क, या अशक्त वर्ण, या अन्य विशेष वर्णों में रिक्त स्थान से बच गए हैं तो यह विफल हो जाएगा?
IQAndreas

97

उपयोग करें "$@"(सभी POSIX कंपेटिबल्स के लिए काम करता है )।

[...], बैश में "$ @" वैरिएबल है, जो रिक्त स्थान द्वारा अलग किए गए सभी कमांड-लाइन मापदंडों का विस्तार करता है।

से बैश उदाहरण के द्वारा


6
तो "$ @" न केवल $ @ के आसपास बोली है, बल्कि प्रभाव में एक अलग से बनाया चर?
बेन

5
@ इसे एक एकल चर है, लेकिन इसके चारों ओर दोहरे उद्धरण चिह्नों (टूटे हुए) से उपयोगी मूल्य की आवश्यकता होती है $*। मेरा मानना ​​है कि यहां ऐतिहासिक प्रगति हुई है; $*डिज़ाइन के अनुसार काम नहीं किया, इसलिए $@इसे बदलने के लिए आविष्कार किया गया था; लेकिन उद्धृत नियम वे क्या हैं, इसके बारे में दोहरे उद्धरण चिह्नों की आवश्यकता है (या यह टूटे हुए $*शब्दार्थों की ओर वापस लौट जाएगा )।
ट्रिपल डी

7
"तो" $ @ "न केवल $ @ के आसपास बोली है बल्कि प्रभाव में एक अलग से बनाया चर?" - सभी इरादों और उद्देश्यों के लिए, हाँ: stackoverflow.com/a/28099707/162094
स्टुअर्ट बर्ग

1
यदि आप एक स्क्रिप्ट युक्त फोन echo "$@"के रूप में ./script.sh a "b c" dतो तुम सिर्फ पाने a b c dके बजाय a "b c" dजो बहुत अलग है।
इसरांडी

7
@isarandi हालांकि यह सच है कि आउटपुट में अब उद्धरण शामिल नहीं हैं, यही आप उम्मीद करेंगे ... लेकिन बाकी का आश्वासन दिया कि स्क्रिप्ट के भीतर, echoतीन तर्क मिलते हैं: "a" "b c" "d"(फिर शेल उनके स्ट्रिंग विस्तार के हिस्से के रूप में एक साथ जुड़ जाता है)। लेकिन अगर आपने इस्तेमाल किया है तो आपको for i in "$@"; do echo $i; doneमिल जाएगा a⏎b c⏎d
FeRD

64

मुझे लगता है कि यह अच्छी तरह से उत्तर दिया गया है, लेकिन यहाँ "$ @" $ @ "$ *" और $ * के बीच तुलना है

परीक्षण स्क्रिप्ट की सामग्री:

# cat ./test.sh
#!/usr/bin/env bash
echo "================================="

echo "Quoted DOLLAR-AT"
for ARG in "$@"; do
    echo $ARG
done

echo "================================="

echo "NOT Quoted DOLLAR-AT"
for ARG in $@; do
    echo $ARG
done

echo "================================="

echo "Quoted DOLLAR-STAR"
for ARG in "$*"; do
    echo $ARG
done

echo "================================="

echo "NOT Quoted DOLLAR-STAR"
for ARG in $*; do
    echo $ARG
done

echo "================================="

अब, विभिन्न तर्कों के साथ परीक्षण स्क्रिप्ट चलाएँ:

# ./test.sh  "arg with space one" "arg2" arg3
=================================
Quoted DOLLAR-AT
arg with space one
arg2
arg3
=================================
NOT Quoted DOLLAR-AT
arg
with
space
one
arg2
arg3
=================================
Quoted DOLLAR-STAR
arg with space one arg2 arg3
=================================
NOT Quoted DOLLAR-STAR
arg
with
space
one
arg2
arg3
=================================

1
इस जवाब के लिए अच्छा प्रदर्शन और योगदान।
मैरिलिन

33
#!/usr/bin/env bash
while [ "$1" != "" ]; do
  echo "Received: ${1}" && shift;
done;

बस सोचा कि यह थोड़ा अधिक उपयोगी हो सकता है जब यह परीक्षण करने की कोशिश की जाए कि आपकी स्क्रिप्ट में कैसे आर्गन आते हैं


6
यह निश्चित रूप से उनके प्रश्न का उत्तर देने में मदद नहीं करता था लेकिन यह वास्तव में उपयोगी है। upvoted!
डारियो रूसो

2
जब कोई खाली पैरामीटर पास होता है तो यह टूट जाता है। आप के लिए जाँच करनी चाहिए$#
सेबी

अच्छा आर्ग टेस्टर, एक तर्क के रूप में , इस बात पर सहमत है "", ''अगर कोई आर्गन्स नहीं थे तो यह चुप है। मैंने इसे ठीक करने की कोशिश की, लेकिन इसके लिए लूप और काउंटर की जरूरत है $#। मैंने इसे अंत में जोड़ा:echo "End of args or received quoted null"
मर्लिन

8

मेरे SUN यूनिक्स की बहुत सी सीमाएँ हैं, यहां तक ​​कि "$ @" को भी वांछित नहीं समझा गया था। मेरा समाधान $ {@} है। उदाहरण के लिए,

#!/bin/ksh
find ./ -type f | xargs grep "${@}"

वैसे, मुझे यह विशेष स्क्रिप्ट करनी थी क्योंकि मेरा यूनिक्स भी grep -r का समर्थन नहीं करता है


यह एक बैश प्रश्न है; आप का उपयोग कर रहे हैंksh
ट्रिपल

6

यदि आप $@अन्य वर्णों के साथ एक उद्धृत स्ट्रिंग में शामिल हैं, तो कई तर्क होने पर व्यवहार बहुत अजीब है, केवल पहला तर्क उद्धरण के अंदर शामिल है।

उदाहरण:

#!/bin/bash
set -x
bash -c "true foo $@"

पैदावार:

$ bash test.sh bar baz
+ bash -c 'true foo bar' baz

लेकिन पहले एक अलग चर को असाइन करना:

#!/bin/bash
set -x
args="$@"
bash -c "true foo $args"

पैदावार:

$ bash test.sh bar baz
+ args='bar baz'
+ bash -c 'true foo bar baz'

3
मैं इस बात से इंकार नहीं करूंगा कि यह असंतोषजनक है, लेकिन यह वास्तव में शब्दार्थ के अर्थ के भीतर है "$@"। यह $@और के बीच महत्वपूर्ण अंतर को स्पष्ट करने में मदद करता है $*, और वे दोनों क्यों उपयोगी हैं। से bash(1)आदमी पेज विशेष पैरामीटर अनुभाग: " *- विस्तार दोहरे उद्धरण चिह्नों के भीतर होता है, यह एक शब्द के लिए प्रत्येक पैरामीटर [...] यही कारण है कि है, के मूल्य के साथ बढ़ती है "$*"बराबर है करने के लिए "$1c$2c..."है, जहां cहै [ $IFS]।" और वास्तव में, अपने पहले उदाहरण के $*बजाय $@दूसरे संस्करण के समान आउटपुट प्राप्त होगा।
FeRD

2
अब, कि तुलना करें "$@"। मैन पेज से फिर से: " @- जब विस्तार दोहरे कोट्स के भीतर होता है, तो प्रत्येक पैरामीटर एक अलग शब्द में फैलता है। यह ... के "$@"बराबर है "$1" "$2"... यदि डबल-कोटेड विस्तार एक शब्द के भीतर होता है, तो पहले पैरामीटर का विस्तार शामिल हो जाता है। मूल शब्द के शुरुआती भाग के साथ, और अंतिम पैरामीटर के विस्तार को मूल शब्द के अंतिम भाग के साथ जोड़ा जाता है। " ... और वास्तव में, यदि आपका कोड था bash -c "true foo $@ bar baz", तो इसे test.sh one twoनेट के रूप में चलाना होगा bash -c 'true foo one' 'two bar baz'
FeRD

1
डॉक्स उद्धरण और के बारे में जानकारी के लिए धन्यवाद $*, मुझे लगता है कि यह मौजूद है भूलने के लिए लगता है ..
कॉलिनम

हे। $@जब मैं पहली बार शेल स्क्रिप्टिंग शुरू कर रहा था , तब मैं इसके विपरीत था , बस कर्षण प्राप्त कर रहा था, मुझे अभी भी अपने आप को यह याद दिलाना है। "$*"लिपियों में इस्तेमाल किया जाना आम था ... तब लेखक को एहसास होता था कि यह उनके सभी तर्कों को एक साथ तोड़ रहा है, इसलिए वे शब्द-विभाजन के साथ जटिल बकवास के सभी तरीके आज़माएंगे "$*", या [पुनः] लूपिंग करके एक arg सूची को इकट्ठा करेंगे। से अधिक shiftउन्हें एक एक करके नीचे खींचने के लिए ... बस का उपयोग कर $@हल करती है यह। (मदद करता है कि बैश सरणी सदस्यों को एक्सेस करने के लिए एक ही mnemonic का उपयोग करता है, भी: ${var[*]}उन सभी के लिए एक शब्द के रूप में, ${var[@]}शब्दों की सूची के लिए।)
FeRD

यहाँ वास्तविक समस्या यह है कि आप bash -cएक तरह से उपयोग कर रहे हैं जो बिल्कुल समझ में नहीं आता है।
ट्रिपलआई

4

कभी-कभी आप अपने सभी तर्कों को पारित करना चाहते हैं, लेकिन एक ध्वज से पहले (जैसे --flag)

$ bar --flag "$1" --flag "$2" --flag "$3"

आप इसे निम्न तरीके से कर सकते हैं:

$ bar $(printf -- ' --flag "%s"' "$@")

ध्यान दें: अतिरिक्त फ़ील्ड विभाजन से बचने के लिए, आपको उद्धरण देना होगा %sऔर $@, एक स्ट्रिंग होने से बचने के लिए, आप के सबस्क्रिप्शन को उद्धृत नहीं कर सकते printf


3

ठीक काम करता है, सिवाय इसके कि आपके पास स्थान हैं या पात्र बच गए हैं। मुझे इस मामले में तर्कों को पकड़ने और स्क्रिप्ट के अंदर एक ssh को भेजने का तरीका नहीं मिला।

यह उपयोगी हो सकता है लेकिन इतना बदसूरत है

_command_opts=$( echo "$@" | awk -F\- 'BEGIN { OFS=" -" } { for (i=2;i<=NF;i++) { gsub(/^[a-z] /,"&@",$i) ; gsub(/ $/,"",$i );gsub (/$/,"@",$i) }; print $0 }' | tr '@' \' )

3

यहाँ बहुत सारे उत्तर , उद्धरण के साथ $@या $*बिना अनुशंसा करते हैं, हालांकि कोई भी यह नहीं बताता है कि ये वास्तव में क्या करते हैं और आपको इस तरह से क्यों करना चाहिए। तो मुझे इस उत्तर से इस उत्कृष्ट सारांश को चोरी करने दें :

यहां छवि विवरण दर्ज करें

ध्यान दें कि उद्धरण सभी अंतर बनाते हैं और उनके बिना दोनों समान व्यवहार करते हैं।

अपने उद्देश्य के लिए, मुझे एक लिपि से दूसरी लिपि में मापदंडों को पारित करने की आवश्यकता है और इसके लिए सबसे अच्छा विकल्प है:

# file: parent.sh
# we have some params passed to parent.sh 
# which we will like to pass on to child.sh as-is

./child.sh $*

कोई उद्धरण नहीं नोटिस और $@ऊपर की स्थिति में भी काम करना चाहिए।


2

bar "$@" के बराबर होगा bar "$1" "$2" "$3" "$4"

ध्यान दें कि उद्धरण चिह्न महत्वपूर्ण हैं!

"$@", $@, "$*"या $*होगा प्रत्येक व्यवहार थोड़ा बचने और संयोजन जिसका विवरण के बारे में अलग अलग stackoverflow जवाब

बारीकी से संबंधित उपयोग का मामला इस तरह एक तर्क के अंदर दिए गए सभी तर्क दे रहा है :

bash -c "bar \"$1\" \"$2\" \"$3\" \"$4\""

मैं इसे प्राप्त करने के लिए @ kvantour के उत्तर की भिन्नता का उपयोग करता हूं:

bash -c "bar $(printf -- '"%s" ' "$@")"

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