रिवर्स ऑर्डर में शेल के तर्क मुद्रित करें


12

मैं थोड़ा फंस गया हूं। मेरा काम तीसरे और चौथे को छोड़कर उल्टे क्रम में मेरी स्क्रिप्ट के तर्कों को प्रिंट करना है।

मेरे पास यह कोड क्या है:

#!/bin/bash

i=$#
for arg in "$@"
do
    case $i
    in
        3) ;;
        4) ;;
        *) eval echo "$i. Parameter: \$$i";;
    esac
    i=`expr $i - 1`
done

जैसा कि मुझे eval (PHP के लिए शुभकामनाएं) से नफरत है, मैं इसके बिना एक समाधान की तलाश कर रहा हूं लेकिन मैं एक खोजने में सक्षम नहीं हूं।

मैं तर्क की स्थिति को गतिशील रूप से कैसे परिभाषित कर सकता हूं?

पुनश्च: नहीं इसका कोई होमवर्क नहीं है, मैं एक परीक्षा के लिए शेल सीख रहा हूं इसलिए मैं पुरानी परीक्षाओं को हल करने का प्रयास करता हूं।

जवाबों:


13

evalडायनेमिक रूप से चुनी गई स्थिति द्वारा स्थितीय पैरामीटर तक पहुंचने का एकमात्र पोर्टेबल तरीका है। यदि आप स्पष्ट रूप से मानों (जो आप उपयोग नहीं कर रहे हैं) के बजाय सूचकांक पर लूप किए गए तो आपकी स्क्रिप्ट स्पष्ट हो जाएगी। ध्यान दें कि आपको exprतब तक ज़रूरत नहीं है जब तक आप अपनी स्क्रिप्ट को एंटीक बॉर्न गोले में चलाना नहीं चाहते हैं; $((…))POSIX में अंकगणित है। evalसबसे छोटे संभव टुकड़े के उपयोग को सीमित करें ; उदाहरण के लिए, उपयोग न करें eval echo, मान को एक अस्थायी चर में निर्दिष्ट करें।

i=$#
while [ "$i" -gt 0 ]; do
  if [ "$i" -ne 3 ] && [ "$i" -ne 2 ]; then
    eval "value=\${$i}"
    echo "Parameter $i is $value"
  fi
  i=$((i-1))
done

बैश में, आप ${!i}उस पैरामीटर के मूल्य का उपयोग कर सकते हैं जिसका नाम है $i। यह तब काम करता है जब $iया तो एक नामित पैरामीटर या एक संख्या है (एक स्थितिगत पैरामीटर को दर्शाते हुए)। जब आप इस पर हों, तो आप अन्य बैश सुविधा सुविधाओं का उपयोग कर सकते हैं।

for ((i=$#; i>0; i--)); do
  if ((i != 3 && i != 4)); then
    echo "Parameter $i is ${!i}"
  fi
done

मैं उपयोग नहीं कर सकता argक्योंकि वे सही ढंग से आदेश दिए गए हैं और रिवर्स में नहीं। के उपयोग के लिए expr, मैं केवल मानक का उपयोग करने के लिए सीमित हूं।
वॉरेनफैथ

1
अगर आपकी स्क्रिप्ट शुरू होती है #!/bin/bash, तो आप उपयोग कर सकते हैं ${!i}और (())। यदि आप मानक श से चिपकना चाहते हैं, तो ये उपलब्ध नहीं हैं, लेकिन $((…))है।
गिल्स एसओ- बुराई को रोकें '

ठीक है, मुझे लगता है कि मैं इस के साथ काम कर सकता हूं :)
WarrenFaith

ध्यान दें कि एंटीक बॉर्न गोले वैसे भी $ 9 से परे स्थितीय मापदंडों तक नहीं पहुंच पाएंगे।
स्टीफन चेज़लस

1
evalहै केवल पोर्टेबल रास्ता रयान से पता चला है के रूप में
स्टीफन चेज़लस

7

मैं reverseअपने रास्ते पर एक स्क्रिप्ट रखता हूं जो ऐसा करता है:

#!/bin/sh

if [ "$#" -gt 0 ]; then
    arg=$1
    shift
    reverse "$@"
    printf '%s\n' "$arg"
fi

उदाहरण का उपयोग:

$ reverse a b c '*' '-n'
-n
*
c
b
a

आप एक समर्पित स्क्रिप्ट के बजाय एक फ़ंक्शन का उपयोग कर सकते हैं।


ध्यान दें कि एक (अब तक पोस्ट किए गए अन्य उत्तरों के विपरीत) बॉर्न शेल में भी काम करेगा (ऐसा नहीं है कि आजकल उस शेल का उपयोग करने का कोई कारण नहीं है)
स्टीफन चेज़लस

@ स्टीफनचेज़ेलस: क्यों बोली $#? क्या यह एक गैर-नकारात्मक पूर्णांक के अलावा कुछ भी हो सकता है?
जी-मैन का कहना है कि मोनिका '

2
@ जी-मैन, सूची के संदर्भ में एक चर को छोड़ कर विभाजन + ग्लोब ऑपरेटर का आह्वान कर रहा है। ऐसा कोई कारण नहीं है कि आप इसे यहां लागू करना चाहते हैं। इसका चर की सामग्री से कोई लेना-देना नहीं है। अंत की ओर unix.stackexchange.com/a/171347 भी देखें । यह भी ध्यान दें कि कुछ गोले (उदाहरण के लिए, पॉश) अभी भी पर्यावरण से IFS को विरासत में प्राप्त करते हैं।
स्टीफन चेज़लस

मैंने पाया कि, एंड्रॉइड पर, मुझे घोषणा करनी थीlocal arg=$1
स्टारफ्री

2

यह निष्कासन का एक सही और गैर-खतरनाक उपयोग है। आप उस सामग्री को पूरी तरह से नियंत्रित करते हैं जो आप evalआईएनजी हैं।

यदि यह अभी भी आपको बुरी भावना देता है, तो यदि आप पोर्टेबिलिटी की परवाह नहीं करते हैं, तो आप बैश के ${!i}अप्रत्यक्ष वाक्य-विन्यास का उपयोग कर सकते हैं ।


तो ${!i}मानक वाक्यविन्यास का हिस्सा नहीं है?
वॉरेनफेथ

नहीं, यह बैशवाद है। यहाँ POSIX पैरामीटर विस्तार हैं: pubs.opengroup.org/onlinepubs/009695399/utilities/…
Shawn J. Goff

2

स्थितीय मानदण्डों में न्यूलाइन वर्ण नहीं हैं:

[ "$#" -gt 0 ] && printf '%s\n' "$@" | #print in order
sed '3,4 d' |                          #skip 3 and 4
tac                                    #reverse (try tail -r on
                                       #non-GNU systems).

परीक्षा:

set 1 2 3 4 5 6
printf '%s\n' "$@" | 
sed '3,4 d' |
tac

परीक्षण उत्पादन:

6
5
2
1

1

के साथ zsh:

$ set a 'foo bar' c '' '*'
$ printf '<%s>\n' "${(Oa)@}"
<*>
<>
<c>
<foo bar>
<a>

Oaउल्टे सरणी सूचकांकों में विस्तार पर सरणी तत्वों को सॉर्ट करने के लिए एक पैरामीटर विस्तार ध्वज है ।

3 और 4 को बाहर करने के लिए:

$ printf '<%s>\n' "${(Oa)@[5,-1]}" "${(Oa)@[1,2]}"
<*>
<foo bar>
<a>

0

मूल रूप से किसी भी शेल के साथ:

printf '{ PS4=\${$(($#-$x))}; } 2>&3; 2>&1\n%.0s' |
x=LINENO+1 sh -sx "$@" 3>/dev/null

और आपको उप-भागों का उपयोग करने की आवश्यकता नहीं है । उदाहरण के लिए:

set -x a b c
{ last= PS4=\${last:=\${$#}}; set +x; } 2>/dev/null
echo "$last"

... प्रिंट ...

c

और यहाँ एक शेल फ़ंक्शन है जो aliasआपके लिए एक शेल सेट कर सकता है जो आगे या पीछे के तर्कों को प्रिंट करेगा:

tofro() case $1 in (*[!0-9]*|'') ! :;;(*) set "$1"
        until   [ "$1" -eq "$(($#-1))" ]    &&
                shift && alias args=":; printf \
            \"%.\$((\$??\${#*}:0))s%.\$((!\$??\${#*}:0))s\n\" $* "
        do      [ "$#" -gt 1 ] &&
                set "$@ \"\${$#}\" " '"${'"$((1+$1-$#))"'}"' ||
                set "$1" '"$1" "${'"$1"'}"'
        done;   esac

यह किसी भी तर्क के लिए शाब्दिक मूल्यों को संग्रहीत करने का प्रयास नहीं करता है, बल्कि यह इस तरह एक स्ट्रिंग डालता है args alias:

:;printf    "%.$(($??${#*}:0))s%.$((!$??${#*}:0))s\n" \
            "$1" "${3}" "${2}"  "${2}" "${3}"  "${1}"

... और इसलिए केवल पीछे और आगे के मापदंडों को संदर्भित करता है। यह एक तर्क के रूप में दी गई गणना तक संग्रहीत करेगा। और इसलिए उपरोक्त aliasकी तरह उत्पन्न किया गया था:

tofro 3

printfपिछले कमांड के रिटर्न वैल्यू के आधार पर व्यवहार प्रभावित होता है - जो हमेशा :शून्य कमांड होता है, और इसलिए आमतौर पर सच होता है। printfहर बार अपने तर्कों के आधे हिस्से को छोड़ देता है - जो कि डिफ़ॉल्ट रूप से, सबसे छोटी संख्या से सबसे बड़ी संख्या तक छपे हुए तर्कों को प्राप्त करेगा। हालांकि, अगर आप अभी करते हैं:

! args

... यह उन्हें उल्टा छापता है।

क्योंकि उपनाम किसी भी शाब्दिक मूल्यों को संग्रहीत नहीं करता है, इसका मूल्य स्थिर रहता है जबकि वास्तविक args बदल सकता है, लेकिन यह अभी भी कई के रूप में संदर्भित करेगा। उदाहरण के लिए:

set one two three
tofro 3
args; ! args
shift; args; ! args

... जो प्रिंट करता है ...

one
two
three
three
two
one
two
three


three
two

लेकिन उपनाम को रीसेट करना जैसे किया जा सकता है:

tofro 2
args; ! args

... और इसलिए यह प्रिंट ...

two
three
three
two

-3
declare -a argv=( "$@" )
for (( i=$((${#argv[@]}-1)) ; i>=0 ; i=$(($i-1)) )) ; do
        echo "${argv[$i]}"
        # use "${argv[$i]}" in here...
done

2
कोई स्पष्टीकरण नहीं, अच्छा है। मेरे नीचे से। समझाएं कि आपका कोड क्या करता है और मैं अपना विचार बदल सकता हूं।
वॉरेनफैथ

3
को सरल किया जा सकता हैfor ((i = $# - 1; i >= 0; i--))
स्टीफन चेज़लस

क्या मुझे मतिभ्रम है? मुझे लगा कि मैंने इस प्रश्न में ऐसे शब्द देखे हैं जिनमें कहा गया है कि "तर्कों को मुद्रित करें ... तीसरे और चौथे को छोड़कर"।
जी-मैन का कहना है कि मोनिका '

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