शेल स्क्रिप्ट में शिफ्ट का उपयोग करने का उद्देश्य क्या है?


118

मैं इस स्क्रिप्ट पर आया हूं:

#! /bin/bash                                                                                                                                                                                           

if (( $# < 3 )); then
  echo "$0 old_string new_string file [file...]"
  exit 0
else
  ostr="$1"; shift
  nstr="$1"; shift  
fi

echo "Replacing \"$ostr\" with \"$nstr\""
for file in $@; do
  if [ -f $file ]; then
    echo "Working with: $file"
    eval "sed 's/"$ostr"/"$nstr"/g' $file" > $file.tmp 
    mv $file.tmp $file
  fi  
done

उन लाइनों का क्या अर्थ है जहां वे उपयोग करते हैं shift? मुझे लगता है कि स्क्रिप्ट का उपयोग कम से कम तर्कों के साथ किया जाना चाहिए ...?

जवाबों:


141

shiftएक bashअंतर्निर्मित है जिसमें तर्क सूची की शुरुआत से तर्कों को हटाया जाता है। यह देखते हुए कि स्क्रिप्ट के लिए प्रदान की 3 तर्कों में उपलब्ध हैं $1, $2, $3, तो एक कॉल करने के लिए shift कर देगा $2नया $1। A पुराने shift 2दो को नया बनाकर शिफ्ट करेगा । अधिक जानकारी के लिए यहां देखें:$1$3


25
+1 नोट यह नहीं कर रहा है घूर्णन उन्हें, यह है स्थानांतरण उन्हें बंद (तर्कों की) सरणी। शिफ्ट / अनशिफ्ट और पॉप / पुश इस सामान्य प्रकार के हेरफेर के लिए सामान्य नाम हैं (देखें, उदाहरण के लिए, बैश के pushdऔर popd)।
गोल्डीलॉक्स


@goldilocks बहुत सच है। "घुमाने" के बजाय मुझे दूसरे शब्द का उपयोग करने का बेहतर तरीका मिल जाना चाहिए, कुछ इस तरह कि "तर्क चर में तर्क को आगे बढ़ाएं"। वैसे भी मुझे उम्मीद है कि पाठ में उदाहरण और संदर्भ के लिंक ने इसे स्पष्ट रूप से स्पष्ट कर दिया होगा।
मानवता

हालाँकि स्क्रिप्ट में उल्लेख है bash, प्रश्न सभी गोले के लिए सामान्य है, इसलिए पॉज़िक्स
calandoa

32

गोल्डीलॉक्स 'टिप्पणी और मानवता के संदर्भ का वर्णन के रूप में, shiftस्थितीय मानकों (reassigns $1, $2आदि) ताकि $1के पुराने मूल्य पर ले जाता $2, $2के मूल्य पर ले जाता है $3आदि, *   के पुराने मूल्य $1खारिज कर दिया है। ( $0नहीं बदला गया है।) ऐसा करने के कुछ कारणों में शामिल हैं:

  • यह आपको दसवें तर्क (यदि कोई है) को अधिक आसानी से एक्सेस करने देता है।  $10काम नहीं करता है - यह $1एक के साथ संक्षिप्त रूप में व्याख्या की जाती है 0 (और इसलिए कुछ ऐसा उत्पादन कर सकता है Hello0)। एक के बाद shift, दसवां तर्क बन जाता है $9। (हालांकि, अधिकांश आधुनिक गोले में, आप उपयोग कर सकते हैं ${10}।)
  • जैसा कि शुरुआती के लिए बैश गाइड प्रदर्शित करता है, इसका उपयोग तर्कों के माध्यम से लूप करने के लिए किया जा सकता है। IMNSHO, यह अनाड़ी है; forउसके लिए बेहतर है।
  • जैसा कि आपकी उदाहरण लिपि में है, यह कुछ को छोड़कर सभी तर्कों को उसी तरह से संसाधित करना आसान बनाता है। उदाहरण के लिए, आपकी स्क्रिप्ट में, $1और $2टेक्स्ट स्ट्रिंग्स हैं, जबकि $3अन्य सभी पैरामीटर फ़ाइल नाम हैं।

तो यहां बताया गया है कि यह कैसे खेलता है। मान लीजिए कि आपकी स्क्रिप्ट को कहा जाता है Patryk_scriptऔर इसे कहा जाता है

Patryk_script USSR Russia Treaty1 Atlas2 Pravda3

स्क्रिप्ट देखती है

$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3

कथन ostr="$1"चर ostrको सेट करता है USSR। पहला shiftबयान निम्नानुसार स्थितीय मापदंडों को बदलता है:

$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3

कथन nstr="$1"चर nstrको सेट करता है Russia। दूसरा shiftकथन स्थितिगत मापदंडों को निम्नानुसार बदलता है:

$1 = Treaty1
$2 = Atlas2
$3 = Pravda3

और फिर forलूप बदल जाता है USSR( $ostr) से Russia( $nstr) फाइल Treaty1में Atlas2, और Pravda3



स्क्रिप्ट के साथ कुछ समस्याएं हैं।

  1. $ @ में फ़ाइल के लिए; करना

    यदि स्क्रिप्ट के रूप में लागू किया गया है

    पैट्रीक_स्क्रिप्ट यूएसएसआर रूस ट्रीटी 1 "वर्ल्ड एटलस 2" प्रवीडा 3

    यह देखता है

    $ 1 = यूएसएसआर
    $ 2 = रूस
    $ 3 = संधि 1
    $ 4 = विश्व एटलस 2
    $ 5 = प्रावदा 3

    लेकिन, क्योंकि $@उद्धृत नहीं है, में अंतरिक्ष World Atlas2उद्धृत नहीं है, और forपाश सोचता है कि यह चार फ़ाइलें हैं: Treaty1, World, Atlas2, और Pravda3। यह या तो होना चाहिए

    "$ @" में फ़ाइल के लिए; करना

    (तर्कों में किसी विशेष वर्ण को उद्धृत करने के लिए) या बस

    फ़ाइल के लिए

    (जो लंबे संस्करण के बराबर है)।

  2. eval "sed" / "$ ostr" / "$ nstr" / g '$ फ़ाइल "

    इसके लिए कोई ज़रूरत नहीं है eval, और कैन के लिए अनियंत्रित उपयोगकर्ता इनपुट को पारित evalकरना खतरनाक हो सकता है। उदाहरण के लिए, यदि स्क्रिप्ट के रूप में लागू किया गया है

    पैट्रीक_स्क्रिप्ट "'; आरएम *;" "रूस ट्रीटी 1 एटलस 2 प्रावदा 3

    इसे अंजाम देंगे rm *! यह एक बड़ी चिंता का विषय है अगर स्क्रिप्ट को उन विशेषाधिकारों के साथ चलाया जा सकता है जो उपयोगकर्ता को आमंत्रित करते हैं; उदाहरण के लिए, यदि इसे sudoवेब इंटरफ़ेस से चलाया या चलाया जा सकता है। यह शायद इतना महत्वपूर्ण नहीं है यदि आप इसे अपने आप के रूप में, अपनी निर्देशिका में उपयोग करते हैं। लेकिन इसे बदला जा सकता है

    sed "s / $ ostr / $ nstr / g" "$ फ़ाइल"

    यह अभी भी कुछ जोखिम है, लेकिन वे बहुत कम गंभीर हैं।

  3. if [ -f $file ], > $file.tmpऔर mv $file.tmp $file होना चाहिए if [ -f "$file" ], > "$file.tmp"और mv "$file.tmp" "$file", क्रमशः, उन फ़ाइल नामों को संभालने के लिए जो उनमें रिक्त स्थान (या अन्य मज़ेदार वर्ण) हो सकते हैं। ( eval "sed …कमांड उन नामों को भी दर्ज करता है जिनके पास रिक्त स्थान है।)


* shift एक वैकल्पिक तर्क लेता है: एक सकारात्मक पूर्णांक जो निर्दिष्ट करता है कि कितने मापदंडों को स्थानांतरित करना है। डिफ़ॉल्ट एक ( 1) है। उदाहरण के लिए, shift 4का कारण बनता है $5 बनने के लिए $1, $6बनने के लिए $2, और इतने पर। (ध्यान दें कि शुरुआती के लिए बैश गाइड में उदाहरण गलत है।) और इसलिए आपकी स्क्रिप्ट को कहने के लिए संशोधित किया जा सकता है

ostr="$1"
nstr="$2"
shift 2

जिसे अधिक स्पष्ट माना जा सकता है।



नोट नोट / चेतावनी:

विंडोज कमांड प्रॉम्प्ट (बैच फ़ाइल) भाषा भी एक SHIFTकमांड का समर्थन करती है , जो मूल रूप से shiftयूनिक्स के गोले में कमांड के समान काम करती है , एक हड़ताली अंतर के साथ, जिसे मैं छिपाने की कोशिश करूंगा ताकि लोग इसे भ्रमित न हों।

  • एक कमांड की तरह SHIFT 4एक त्रुटि है, "SHIFT कमांड के लिए अमान्य पैरामीटर" त्रुटि संदेश।
  • SHIFT /n, जहां n0 और 8 के बीच पूर्णांक है, मान्य है - लेकिन यह बार-बार शिफ्ट नहीं होता है । यह एक बार बदलाव, के साथ शुरू n  वें तर्क। तो कारण बनता है (पाँचवाँ तर्क) बनने के लिए , और इसी तरह, तर्कों को छोड़कर 3 अकेले।n SHIFT /4%5%4,  %6%5


2
shiftलागू किया जा सकता करने के लिए while, untilऔर यहां तक कि forएक साधारण कर सकते हैं की तुलना में अधिक सूक्ष्म तरीके में सरणियों से निपटने के लिए लूप forलूप। मुझे अक्सर यह forलूप्स में उपयोगी लगता है जैसे ... set -f -- $args; IFS=$split; for arg do set -- $arg; shift "${number_of_fields_to_discard}" && fn_that_wants_split_arg "$arg"; done
mikeserv

3

सबसे सरल स्पष्टीकरण यह है। कमांड पर विचार करें:

/bin/command.sh SET location Cebu
/bin/command.sh SET location Cebu, Philippines 6014 

shiftआपकी मदद के बिना स्थान का पूरा मूल्य नहीं निकाला जा सकता क्योंकि यह मान मनमाने ढंग से लंबा हो सकता है। आप दो बार, आर्ग शिफ्ट जब SETऔर locationहै कि इस तरह निकाल दिए जाते हैं:

x="$@"
echo "location = $x"

$@बात पर बहुत लंबा घूरना । इसका मतलब है, यह xरिक्त स्थान और अल्पविराम के बावजूद पूर्ण स्थान को चर में सहेज सकता है। इसलिए सारांश में, हम कॉल करते हैं shiftऔर फिर बाद में हम वैरिएबल से जो बचा है उसका मान निकालते हैं $@

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

#!/bin/sh
#

[ $# -eq 0 ] && return 0

a=$1
shift
b=$@
echo $a
[ -n "$b" ] && echo $b

स्पष्टीकरण : shiftचर b के बाद बाकी सामान सम्‍मिलित किया जाएगा, जिसमें रिक्त स्थान या आदि की कोई बात नहीं है। [ -n "$b" ] && echo $bएक सुरक्षा ऐसी है कि हम केवल b को प्रिंट करते हैं यदि उसमें कोई सामग्री है।


(१) यह सरलतम व्याख्या नहीं है। यह एक दिलचस्प कोण है। (२) लेकिन जब तक आप तर्कों का एक गुच्छा (या उन सभी को) में बदलना चाहते हैं, तब तक आप "$*"इसके बजाय उपयोग करने की आदत में पड़ सकते हैं "$@"। (३) मैं आपके उत्तर का उत्थान करने जा रहा था, लेकिन मैंने ऐसा नहीं किया, क्योंकि आप कहते हैं कि "दो बार शिफ्ट" करें, लेकिन आप वास्तव में इसे कोड में नहीं दिखाते हैं। (४) यदि आप चाहते हैं कि कोई स्क्रिप्ट कमांड लाइन से एक बहु-शब्द मान लेने में सक्षम हो, तो संभवतः उपयोगकर्ता को पूरे मूल्य को उद्धरण में रखने की आवश्यकता होती है। … (Cont'd)
स्कॉट

(Cont'd) ... आज आप परवाह नहीं कर सकते हैं, लेकिन आपका दृष्टिकोण आपको कई स्थान ( Philippines   6014), अग्रणी स्थान, अनुगामी स्थान, या टैब रखने की अनुमति नहीं देता है । (५) बीटीडब्लू, आप भी कर सकते हैं कि आप यहाँ क्या कर रहे हैं x="${*:3}"
स्कॉट

मैंने यह समझने की कोशिश की कि आपका '*** एकाधिक स्पेस की अनुमति नहीं देता है ***' टिप्पणी इसलिए आ रही है क्योंकि यह shiftकमांड से संबंधित नहीं है । आप शायद $ @ बनाम $ * सूक्ष्म अंतर का जिक्र कर रहे हैं। लेकिन यह तथ्य अभी भी बना हुआ है, कि ऊपर मेरा स्निपेट स्थान को सही ढंग से निकाल सकता है, चाहे वह कितने भी स्थान पर पीछे हो या सामने की तरफ से कोई फर्क नहीं पड़ता। शिफ्ट के बाद, स्थान में सही स्थान होगा।
टाइपेलॉजिक

2

shift एक FIFO कतार के रूप में कमांड लाइन तर्कों का इलाज करें, यह हर बार इसे लागू करने वाले तत्व को पॉपलेट करता है।

array = [a, b, c]
shift equivalent to
array.popleft
[b, c]
$1, $2,$3 can be interpreted as index of the array.
$# is the length of array
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.