क्या कोई शेल स्क्रिप्ट इसके तर्क को छापती है, जिसे आप शेल प्रॉम्प्ट पर लिखेंगे, उद्धृत किया गया है?


9

एक शेल स्क्रिप्ट में, मेरी समझ यह है कि "$@"स्क्रिप्ट के तर्कों का विस्तार, उन्हें आवश्यकतानुसार उद्धृत करता है। उदाहरण के लिए यह आगे पीछे करने के लिए स्क्रिप्ट तर्क देता है:

gcc -fPIC "$@"

<<<हालांकि बैश पास-टू-स्टड सिंटैक्स का उपयोग करते समय , "@$"यह काम नहीं करता है क्योंकि मैं इसकी अपेक्षा करूंगा।

#!/bin/bash
cat <<< "$@"

स्क्रिप्ट को कॉलिंग के रूप में ./test.sh foo "bar baz"देता है

foo bar baz

मुझे अपेक्षा होगी

foo "bar baz"

क्या कोई शेल स्क्रिप्ट लिखने का एक तरीका है जो कि यह तर्क देता है जैसे कि आप उन्हें शेल प्रॉम्प्ट पर लिखेंगे? उदाहरण के लिए: संकेत में संकेत तर्कों सहित, आगे क्या उपयोग करने के लिए आदेश के रूप में एक संकेत।

जवाबों:


5

खैर, "$@"स्थितीय मापदंडों की सूची में फैलता है, प्रति तर्क एक पैरामीटर प्रतिमान।

जब तुम करोगे:

set '' 'foo bar' $'blah\nblah'
cmd "$@"

cmdउन 3 तर्कों के साथ लागू किया जा रहा है: खाली स्ट्रिंग, foo barऔर blah<newline>blah। शेल execve()सिस्टम कॉल को कुछ इस तरह बुलाएगा:

execve("/path/to/cmd", ["cmd", "", "foo bar", "blah\nblah"], [envvars...]);

यदि आप एक शेल कमांड लाइन (जो कि शेल लैंग्वेज में कोड है) को फिर से संगठित करना चाहते हैं, जो उसी आह्वान को पुन: उत्पन्न करेगा, तो आप कुछ ऐसा कर सकते हैं:

awk -v q="'" '
  function shellquote(s) {
    gsub(q, q "\\" q q, s)
    return q s q
  }
  BEGIN {
    for (i = 1; i < ARGC; i++) {
      printf "%s", sep shellquote(ARGV[i])
      sep = " "
    }
    printf "\n"
  }' cmd "$@"

या zshविभिन्न प्रकार के उद्धरणों के लिए पूछ रहे हैं:

set '' 'foo bar' $'blah\nblah'
$ print -r -- cmd "${(q)@}"
cmd '' foo\ bar blah$'\n'blah
$ print -r -- cmd "${(qq)@}"
cmd '' 'foo bar' 'blah
blah'
$ print -r -- cmd "${(qqq)@}"
cmd "" "foo bar" "blah
blah"
$ print -r -- cmd "${(qqqq)@}"
cmd $'' $'foo bar' $'blah\nblah'

या zsh, bashया , ksh93( bashअन्य गोले के साथ YMMV के लिए ):

$ set '' 'foo bar' $'blah\nblah'
$ printf cmd; printf ' %q' "$@"; printf '\n'
cmd '' foo\ bar $'blah\nblah'

आप शेल के xtrace विकल्प का भी उपयोग कर सकते हैं जो शेल को प्रिंट करने का कारण बनता है जो इसे निष्पादित करने जा रहा है:

(PS4=; set -x; : cmd "$@")
: cmd '' 'foo bar' 'blah
blah'

ऊपर, हमने तर्क के रूप में :नो-ऑप कमांड cmdऔर स्थितीय मापदंडों को चलाया । मेरे खोल ने उन्हें खोल के पुनर्निवेश के लिए उपयुक्त एक अच्छे उद्धृत फैशन में छापा। सभी गोले ऐसा नहीं करते हैं।


5
`"$@"` expands to the script arguments, quoting them as needed

नहीं, ऐसा नहीं है। प्रोग्राम को कॉल करना तर्कों की एक सूची लेता है , प्रत्येक तर्क एक स्ट्रिंग है। जब आप खोल कार्यक्रम चलाने ./test.sh foo "bar baz", यह तीन तर्क के साथ एक फोन बनाता है: ./test.sh, foo, और bar baz। (शून्य तर्क प्रोग्राम का नाम है; यह प्रोग्रामों को यह जानने की अनुमति देता है कि उन्हें किस नाम से पुकारा जाता है।) क्वॉटिंग शेल की एक विशेषता है, न कि प्रोग्राम कॉल की सुविधा। जब यह कॉल करता है तो शेल इस सूची का निर्माण करता है।

"$@"सीधे स्क्रिप्ट या उस फ़ंक्शन में तर्कों की सूची पर कार्य किए गए तर्कों की सूची को कॉपी करता है जहां इसका उपयोग किया जाता है। कोई सूची शामिल नहीं है क्योंकि उन सूचियों पर कोई शेल पार्सिंग नहीं की गई है।

में cat <<< "$@", आप "$@"एक ऐसे संदर्भ में उपयोग कर रहे हैं जहाँ एक एकल स्ट्रिंग की आवश्यकता है। <<<Operator` एक स्ट्रिंग, नहीं स्ट्रिंग की एक सूची की आवश्यकता है। इस संदर्भ में, बैश सूची के तत्वों को लेते हैं और उन्हें बीच में एक स्थान के साथ जोड़ते हैं।

स्क्रिप्ट डीबगिंग के लिए, यदि आप चलाते हैं set -x( set +xबंद करने के लिए), तो यह एक ट्रेस मोड को सक्रिय करता है जहां प्रत्येक कमांड को निष्पादित करने से पहले प्रिंट किया जाता है। बैश में, उस ट्रेस में उद्धरण होते हैं जो कमांड को वापस शेल में पेस्ट करना संभव बनाते हैं (यह हर shकार्यान्वयन का सच नहीं है )।

यदि आपके पास एक स्ट्रिंग है और आप इसे शेल स्रोत सिंटैक्स में बदलना चाहते हैं जो मूल स्ट्रिंग में वापस आ जाता है, तो आप इसे सिंगल कोट्स के साथ घेर सकते हैं, और स्ट्रिंग के अंदर हर एक उद्धरण को बदल सकते हैं '\''

for x do
  printf %s "'${x//\'/\'\\\'\'}' "
done
echo

स्ट्रिंग प्रतिस्थापन सिंटैक्स ksh93 / bash / zsh / mksh-specific है। सादे श में, आपको स्ट्रिंग पर लूप करने की आवश्यकता है।

for raw do
  quoted=
  while case "$raw" in *\'*) true;; *) false;; esac; do
    quoted="$quoted'\\''${raw%%\'*}"
    raw="${raw#*\'}"
  done
  printf %s "'$quoted$raw' "
done
echo

2

"$@" स्क्रिप्ट तर्क का विस्तार, उन्हें आवश्यकतानुसार उद्धृत करते हुए

अच्छी तरह की। व्यावहारिक उद्देश्यों के लिए जो पर्याप्त पास होना चाहिए, और संदर्भ मैनुअल ऐसा कहता है"$@" is equivalent to "$1" "$2" ...

इसलिए, दो मापदंडों के साथ fooऔर bar baz, ये एक जैसे होंगे:

echo "$@"
echo "$1" "$2"
echo "foo" "bar baz"

(सिवाय इसके कि अगर मापदंडों में केवल सादे तारों के बजाय विशेष वर्ण होते हैं, तो वे विस्तार के बाद फिर से विस्तारित नहीं होंगे $@और $1...)

लेकिन अगर हम $@उद्धरणों में मापदंडों द्वारा प्रतिस्थापित पर विचार करते हैं, तो उद्धरण echoदेखने के लिए नहीं होंगे , उसी तरह gccउद्धरण भी नहीं मिलते हैं।

<<<"$@"== "$1" "$2" ...नियम का एक अपवाद है , यह स्पष्ट रूप से उल्लेख किया गया है कि The result is supplied as a single string to the command on its standard inputपैरामीटर और चर विस्तार और दूसरों के बीच उद्धरण हटाने के बाद। तो हमेशा की तरह, <<< "foo"बस fooइनपुट के रूप में देता है , उसी तरह somecmd "foo"केवल fooएक तर्क के रूप में देता है।

स्क्रिप्ट को कॉलिंग ./test.sh foo "bar baz"[...] मैं उम्मीद करूंगा foo "bar baz"

यदि उद्धरण बने रहे, तो यह अभी भी होना चाहिए "foo" "bar baz"। शेल या किसी भी रनिंग कमांड का कोई पता नहीं होता है कि कमांड के चलने पर क्या उद्धृत किया गया था। या अगर बात करने के लिए कोई उद्धरण भी था, तो सिस्टम कॉल केवल शून्य-समाप्त स्ट्रिंग्स की एक सूची प्राप्त करता है और उद्धरण केवल शेल भाषा की एक विशेषता है। अन्य भाषाओं में अन्य सम्मेलन हो सकते हैं।


0

बैश के लिए एक वैकल्पिक समाधान

q='"'; t=( "${@/#/$q}" ); u=( "${t[@]/%/$q}" ); echo ${u[@]}

बैश नेस्टेड प्रतिस्थापन का समर्थन नहीं करता है, इसलिए एक सरणी को पुन: असाइन करने के तरीके को दिखाने के लिए /programming/12303974/assign-array-to-variable#12304017 के लिए धन्यवाद । सरणियों, विस्तार, और पैटर्न प्रतिस्थापन (पैरामीटर के अंतर्गत) पर विवरण के लिए man bash( https://linux.die.net/man/1/bash ) देखें ।

विश्लेषण

बैश कमांड लाइन के मापदंडों को एक सरणी के रूप में रखता है $@

q उद्धृत चरित्र रखती है।

पैरामीटर विस्तार के आसपास डबल कोट्स ${ ... }अलग-अलग तत्वों के रूप में अलग-अलग मापदंडों को संरक्षित करता है और उन्हें लपेटकर ( )आपको एक चर के रूप में उन्हें असाइन करने की अनुमति देता है।

/#/$qएक पैरामीटर विस्तार ^में कोटिंग चार के साथ पैटर्न की शुरुआत (जैसे रेगेक्स ) का विकल्प होता है।

/%/$qएक पैरामीटर विस्तार $में कोटिंग चार्ट के साथ पैटर्न के अंत (जैसे रेगेक्स ) का विकल्प होता है।

मामले का उपयोग करें: कमांड लाइन से ईमेल पते की एक सूची के लिए MySQL क्वेरी

ऊपर दिए गए कथनों का उपयोग करने के लिए ऊपर दिए गए कथनों में कुछ बदलाव किए गए हैं, मापदंडों के बीच अल्पविराम जोड़ सकते हैं, और अंतिम अल्पविराम को बंद कर सकते हैं। और निश्चित रूप से मैं mysql मंगलाचरण में पासवर्ड डालकर खराब हो रहा हूं। इसलिए मुझ पर मुकदमा करो।

q="'"; t=( "${@/#/$q}" ); u="${t[@]/%/$q,}"; v="u.email in( ${u%,} )"
mysql -uprod_program -h10.90.2.11 -pxxxxxxxxxxxx my_database <<END
select ...
from users u
join ....
where $v # <<<<<<<<<<<<<<<<<< here is where all the hard work pays off :-)
group by user_id, prog_id
;
END

बस ध्यान दें कि डबल-कोट्स के साथ उद्धृत करना बैकस्लैश, $-एक्सपेशन और अन्य डबल-कोट्स की सुरक्षा में बहुत मददगार नहीं है । यही कारण है कि अन्य उत्तर स्ट्रिंग के अंदर सिंगल कोट्स को संभालने के लिए कुछ लंबाई में जाते समय सिंगल कोट्स का उपयोग करते हैं, या स्ट्रिंग के एक उद्धृत कॉपी के उत्पादन के लिए शेल की अपनी विशेषताओं का उपयोग करते हैं।
५०:३il

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