यूनिक्स बॉर्न शेल में पहुंचता है


26

मैं बॉर्न शेल ( /bin/sh) में सरणियों का उपयोग करने की कोशिश कर रहा हूं । मैंने पाया कि सरणी तत्वों को आरंभ करने का तरीका है:

arr=(1 2 3)

लेकिन यह एक त्रुटि का सामना कर रहा है:

syntax error at line 8: `arr=' unexpected

अब जिस पद पर मुझे यह सिंटैक्स मिला bash, वह कहता है कि यह है , लेकिन मुझे बॉर्न शेल के लिए कोई अलग सिंटैक्स नहीं मिला। क्या वाक्य रचना भी उसी /bin/shतरह से खड़ी होती है ?


1
इस सवाल की जांच करें stackoverflow.com/questions/9481702/… स्टैक ओवरफ्लो पर
निश्चय

1
Thnx @Nischay ... लिंक आपके द्वारा दी गई पढ़ने के बाद, मैं गूगल में मेरे क्वेरी स्ट्रिंग परिष्कृत और लिंक मिला - docstore.mik.ua/orelly/unix/upt/ch45_34.htm
SubhasisM

जवाबों:


47

/bin/shशायद ही कभी किसी भी सिस्टम पर एक बॉर्न शेल होता है (यहां तक ​​कि सोलारिस जो इसे शामिल करने के लिए अंतिम प्रमुख प्रणाली में से एक था, जो अब सोलिस 11 में अपने / बिन / श के लिए एक पोसिक्स श में बदल गया है)। /bin/sh70 के दशक की शुरुआत में थॉम्पसन शेल था। 1979 में यूनिक्स V7 में बॉर्न शेल ने इसे बदल दिया।

/bin/sh उसके बाद कई वर्षों तक बॉर्न शेल रहा (या अल्मक्विस्ट शेल, बीएसडी पर एक मुक्त पुन: कार्यान्वयन)।

आजकल, /bin/shअधिक सामान्यतः एक दुभाषिया या पोसिक्स shभाषा के लिए एक और है जो स्वयं ksh88 की भाषा के उपसमूह पर आधारित है (और कुछ असंगतताओं के साथ बॉर्न शैल भाषा का एक सुपरसेट)।

बॉर्न शेल या POSIX श भाषा विनिर्देश सरणियों का समर्थन नहीं करते हैं। (स्थितीय पैरामीटर: या बल्कि वे केवल एक सरणी है $1, $2, $@के रूप में है, तो समारोह प्रति एक सरणी में अच्छी तरह से)।

ksh88 के पास एरेज़ थे, जिन्हें आपने सेट किया था set -A, लेकिन यह POSIX श में निर्दिष्ट नहीं किया गया क्योंकि सिंटैक्स अजीब है और बहुत उपयोग करने योग्य नहीं है।

सरणी / सूचियों चर के साथ अन्य गोले में शामिल हैं: csh/ tcsh, rc, es, bash(ज्यादातर ksh93 तरह से कॉपी किया जो ksh वाक्य रचना), yash, zsh, fishएक अलग वाक्य रचना (के साथ एक rcयूनिक्स के उत्तराधिकारी एक बार होने वाली है के खोल, fishऔर zshसबसे सुसंगत जा रहा है वाले) ...

मानक में sh(बॉर्न शेल के आधुनिक संस्करणों में भी काम करता है):

set '1st element' 2 3 # setting the array

set -- "$@" more # adding elements to the end of the array

shift 2 # removing elements (here 2) from the beginning of the array

printf '<%s>\n' "$@" # passing all the elements of the $@ array 
                     # as arguments to a command

for i do # looping over the  elements of the $@ array ($1, $2...)
  printf 'Looping over "%s"\n' "$i"
done

printf '%s\n' "$1" # accessing individual element of the array.
                   # up to the 9th only with the Bourne shell though
                   # (only the Bourne shell), and note that you need
                   # the braces (as in "${10}") past the 9th in other
                   # shells.

printf '%s\n' "$# elements in the array"

printf '%s\n' "$*" # join the elements of the array with the 
                   # first character (byte in some implementations)
                   # of $IFS (not in the Bourne shell where it's on
                   # space instead regardless of the value of $IFS)

(ध्यान दें कि बॉर्न शेल और ksh88 में, ठीक से (बग) काम करने के $IFSलिए स्पेस कैरेक्टर होना चाहिए "$@", और बॉर्न शेल में, आप ऊपर के तत्वों तक नहीं पहुँच सकते $9( ${10}काम नहीं करेंगे, आप अभी भी कर सकते हैं shift 1; echo "$9"या लूप ओवर कर सकते हैं) उन्हें))।


2
धन्यवाद एक टन ... आपका विस्तृत विवरण बहुत मददगार था।
सुभासिम्स

1
यह ध्यान देने योग्य हो सकता है कि कुछ प्रमुख विशेषताओं में स्थितीय बैश सरणियों से अलग हैं। उदाहरण के लिए, वे विरल सरणियों का समर्थन नहीं करते हैं, और चूंकि श में स्लाइसिंग पैरामीटर विस्तार नहीं है, इसलिए आप उपलेस्ट जैसे एक्सेस नहीं कर सकते "${@:2:4}"। यह सुनिश्चित करने के लिए, मैं समानताएं देखता हूं , लेकिन मैं प्रति सरणी के रूप में स्थितीय मापदंडों का संबंध नहीं करता हूं ।
कोजीरो

@kojiro, कुछ हद तक, मैं कहेंगे यह, इसके विपरीत है "$@"एक सरणी की तरह कार्य करता (की सरणियों की तरह csh, rc, zsh, fish, yash, यह अधिक है ...) कॉर्न / बैश "सरणियों" है कि वास्तव में सरणियों नहीं हैं, लेकिन कुछ सकारात्मक पूर्णांकों तक सीमित चाबियों के साथ साहचर्य सरणियों का रूप (उनके पास भी 1 के बजाय 0 से शुरू होने वाले सूचक हैं जैसे कि सरणियों और "$ @" के साथ अन्य सभी गोले में)। गोले के लिए समर्थन करने वाले गोले $ @ का टुकड़ा ही कर सकते हैं (ksh93 / bash के साथ अजीब तरह से $ 0 को जोड़ने के लिए स्थितीय मापदंडों पर जब आप "$ @" स्लाइस करते हैं)।
स्टीफन चेज़लस

3

सादे बॉर्न शेल में कोई सरणियाँ नहीं हैं। आप एक सरणी बनाने और उसका पता लगाने के लिए निम्न तरीके का उपयोग कर सकते हैं:

#!/bin/sh
# ARRAY.sh: example usage of arrays in Bourne Shell

array_traverse()
{
    for i in $(seq 1 $2)
    do
    current_value=$1$i
    echo $(eval echo \$$current_value)
    done
    return 1
}

ARRAY_1=one
ARRAY_2=two
ARRAY_3=333
array_traverse ARRAY_ 3

कोई फर्क नहीं पड़ता कि क्या सरणियों का उपयोग करने के लिए shआप इसे हमेशा बोझिल हो जाएगा चुनें। एक अलग भाषा का उपयोग करने पर विचार करें जैसे कि Pythonया Perlयदि आप तब तक नहीं कर सकते जब तक आप बहुत सीमित मंच के साथ नहीं अटक जाते हैं या कुछ सीखना चाहते हैं।


जवाब के लिए धन्यवाद...!! वास्तव में मैं वास्तव में शेल स्क्रिप्ट में चीजों को सीखने की कोशिश कर रहा हूं ... अन्यथा पायथन में सरणी को लागू करना वास्तव में केक का एक टुकड़ा है। यह एक बड़ा सबक था कि कुछ स्क्रिप्टिंग भाषा मौजूद है जो सरणी का समर्थन नहीं करती है :) एक बात, आपके द्वारा पोस्ट किया गया कोड त्रुटि दे रहा है - "पंक्ति 6 ​​पर वाक्य रचना त्रुटि:` $ 'अप्रत्याशित "... मैं थोड़ा व्यस्त हूं अब, मैं इसे हल हो जाएगा ... plz परेशान मत करो।
सुभासिम्स

@ नोबगेक, बॉर्न शेल में $(...)वाक्य रचना नहीं है । तो आपके पास वास्तव में बॉर्न शेल होना चाहिए। आप सोलारिस 10 पर हैं या उससे पहले? संभावना है कि आपके पास seqया तो नहीं होगा । सोलारिस 10 और इससे पहले, आप shबॉर्न शेल के बजाय एक मानक के लिए / usr / xpg4 / bin / sh चाहते हैं । seqउस तरीके का उपयोग करना बहुत अच्छा नहीं है।
स्टीफन चेज़लस

POSIX बताता है कि $ और `कमांड प्रतिस्थापन में बराबर हैं: लिंक । और seqउस तरीके का उपयोग अच्छा क्यों नहीं है?
अर्कादिअस ड्राज्स्क

2
हाँ, POSIX गोले में, आपको $(...)ओवर पसंद करना चाहिए `, लेकिन OP का /bin/shसंभवतः बॉर्न शेल है, न कि POSIX शेल। seqएक मानक कमांड नहीं होने के अलावा , $(seq 100)इसका मतलब है कि पूरे आउटपुट को मेमोरी में स्टोर करना, और इसका मतलब है कि यह $ IFS के वर्तमान मूल्य पर निर्भर करता है जिसमें न्यूलाइन और अंकों से युक्त नहीं है। सबसे अच्छा उपयोग करने के लिए i=1; while [ "$i" -le 100 ]; ...; i=$(($i + 1)); done(हालांकि वह बॉर्न शेल में भी काम नहीं करेगा)।
स्टीफन चेज़लस

1
@Daenyth मैं इसके विपरीत कहना चाहूंगा: पहले बशीज़ सीखना, और फिर बाद में पोर्टेबल /bin/shसिंटैक्स, लोगों को यह सोचने के लिए प्रेरित करता है कि गलत #!/bin/shशेबंग का उपयोग करना ठीक है , और फिर उनकी स्क्रिप्ट को तोड़ देता है जब अन्य लोग उनका उपयोग करने की कोशिश करते हैं। आपको इस तरह की फ्लेमबैट पोस्ट नहीं करने की सलाह दी जाएगी। :)
जोसप रॉडिन

2

जैसा कि दूसरों ने कहा है, बॉर्न शेल में वास्तविक सरणियाँ नहीं हैं ।

हालांकि, आपको क्या करने की जरूरत है, इस पर निर्भर करते हुए, सीमांकित तार को पर्याप्त होना चाहिए:

sentence="I don't need arrays because I can use delimited strings"
for word in $sentence
do
  printf '%s\n' "$word"
done

यदि विशिष्ट सीमांकक (स्थान, टैब और न्यूलाइन) पर्याप्त नहीं है, तो IFSआप लूप से पहले जो भी परिसीमन चाहते हैं , उसे सेट कर सकते हैं।

और अगर आपको क्रमिक रूप से सरणी बनाने की आवश्यकता है, तो आप बस एक सीमांकित स्ट्रिंग बना सकते हैं।


1
जब तक आप इसे नहीं चाहते (असंभावित), आप शायद ग्लोबिंग को भी निष्क्रिय करना चाहेंगे जो कि ( split+globऑपरेटर) की तरह अछूता चर छोड़ने का एक और प्रभाव है ।
स्टीफन चेज़लस

0

डैश में सरणियों का अनुकरण करने का एक तरीका (यह किसी भी सरणी के किसी भी आयाम के लिए अनुकूलित किया जा सकता है): (कृपया ध्यान दें कि seqकमांड के उपयोग के लिए आवश्यक है कि IFS'' (SPACE = डिफ़ॉल्ट मान) पर सेट हो। आप उपयोग कर सकते हैं while ... do ...या कर सकते हैं। do ... while ...इससे बचने के लिए छोरों (मैं seqकोड क्या करता है के एक बेहतर चित्रण के दायरे में रखा गया है)।

#!/bin/sh

## The following functions implement vectors (arrays) operations in dash:
## Definition of a vector <v>:
##      v_0 - variable that stores the number of elements of the vector
##      v_1..v_n, where n=v_0 - variables that store the values of the vector elements

VectorAddElementNext () {
# Vector Add Element Next
# Adds the string contained in variable $2 in the next element position (vector length + 1) in vector $1

    local elem_value
    local vector_length
    local elem_name

    eval elem_value=\"\$$2\"
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    vector_length=$(( vector_length + 1 ))
    elem_name=$1_$vector_length

    eval $elem_name=\"\$elem_value\"
    eval $1_0=$vector_length
}

VectorAddElementDVNext () {
# Vector Add Element Direct Value Next
# Adds the string $2 in the next element position (vector length + 1) in vector $1

    local elem_value
    local vector_length
    local elem_name

    eval elem_value="$2"
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    vector_length=$(( vector_length + 1 ))
    elem_name=$1_$vector_length

    eval $elem_name=\"\$elem_value\"
    eval $1_0=$vector_length
}

VectorAddElement () {
# Vector Add Element
# Adds the string contained in the variable $3 in the position contained in $2 (variable or direct value) in the vector $1

    local elem_value
    local elem_position
    local vector_length
    local elem_name

    eval elem_value=\"\$$3\"
    elem_position=$(($2))
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    if [ $elem_position -ge $vector_length ]; then
        vector_length=$elem_position
    fi

    elem_name=$1_$elem_position

    eval $elem_name=\"\$elem_value\"
    if [ ! $elem_position -eq 0 ]; then
        eval $1_0=$vector_length
    fi
}

VectorAddElementDV () {
# Vector Add Element
# Adds the string $3 in the position $2 (variable or direct value) in the vector $1

    local elem_value
    local elem_position
    local vector_length
    local elem_name

    eval elem_value="$3"
    elem_position=$(($2))
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    if [ $elem_position -ge $vector_length ]; then
        vector_length=$elem_position
    fi

    elem_name=$1_$elem_position

    eval $elem_name=\"\$elem_value\"
    if [ ! $elem_position -eq 0 ]; then
        eval $1_0=$vector_length
    fi
}

VectorPrint () {
# Vector Print
# Prints all the elements names and values of the vector $1 on sepparate lines

    local vector_length

    vector_length=$(($1_0))
    if [ "$vector_length" = "0" ]; then
        echo "Vector \"$1\" is empty!"
    else
        echo "Vector \"$1\":"
        for i in $(seq 1 $vector_length); do
            eval echo \"[$i]: \\\"\$$1\_$i\\\"\"
            ###OR: eval printf \'\%s\\\n\' \"[\$i]: \\\"\$$1\_$i\\\"\"
        done
    fi
}

VectorDestroy () {
# Vector Destroy
# Empties all the elements values of the vector $1

    local vector_length

    vector_length=$(($1_0))
    if [ ! "$vector_length" = "0" ]; then
        for i in $(seq 1 $vector_length); do
            unset $1_$i
        done
        unset $1_0
    fi
}

##################
### MAIN START ###
##################

## Setting vector 'params' with all the parameters received by the script:
for i in $(seq 1 $#); do
    eval param="\${$i}"
    VectorAddElementNext params param
done

# Printing the vector 'params':
VectorPrint params

read temp

## Setting vector 'params2' with the elements of the vector 'params' in reversed order:
if [ -n "$params_0" ]; then
    for i in $(seq 1 $params_0); do
        count=$((params_0-i+1))
        VectorAddElement params2 count params_$i
    done
fi

# Printing the vector 'params2':
VectorPrint params2

read temp

## Getting the values of 'params2'`s elements and printing them:
if [ -n "$params2_0" ]; then
    echo "Printing the elements of the vector 'params2':"
    for i in $(seq 1 $params2_0); do
        eval current_elem_value=\"\$params2\_$i\"
        echo "params2_$i=\"$current_elem_value\""
    done
else
    echo "Vector 'params2' is empty!"
fi

read temp

## Creating a two dimensional array ('a'):
for i in $(seq 1 10); do
    VectorAddElement a 0 i
    for j in $(seq 1 8); do
        value=$(( 8 * ( i - 1 ) + j ))
        VectorAddElementDV a_$i $j $value
    done
done

## Manually printing the two dimensional array ('a'):
echo "Printing the two-dimensional array 'a':"
if [ -n "$a_0" ]; then
    for i in $(seq 1 $a_0); do
        eval current_vector_lenght=\$a\_$i\_0
        if [ -n "$current_vector_lenght" ]; then
            for j in $(seq 1 $current_vector_lenght); do
                eval value=\"\$a\_$i\_$j\"
                printf "$value "
            done
        fi
        printf "\n"
    done
fi

################
### MAIN END ###
################

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