Unix Bourne Kabuğundaki Diziler


26

Bourne kabuğundaki ( /bin/sh) dizileri kullanmaya çalışıyorum . Dizi elemanlarını başlatmanın yolunun:

arr=(1 2 3)

Ancak bir hatayla karşılaşıyor:

syntax error at line 8: `arr=' unexpected

Şimdi bu sözdizimini bulduğum gönderi bunun için olduğunu söylüyor bash, ancak Bourne kabuğu için ayrı bir sözdizimi bulamadım. Sözdizimi de aynı şekilde duruyor /bin/shmu?


1
Bu soruya bakın stackoverflow.com/questions/9481702/… Yığın taşması üzerine
Nischay

1
Thnx @Nischay ... sağladığınız bağlantıyı okuduktan sonra google benim sorgu dizesi rafine ve bağlantı var - docstore.mik.ua/orelly/unix/upt/ch45_34.htm
SubhasisM

Yanıtlar:


47

/bin/shgünümüzde hiçbir sistemde neredeyse hiç Bourne kabuğu bulunmuyor (dahil edilmesi gereken son büyük sistemlerden biri olan Solaris bile, Solaris 11'deki / bin / sh için POSIX koduna geçti). /bin/sh70'lerin başında Thompson kabuğu oldu. Bourne kabuğu 1979'da Unix V7'de yerini aldı.

/bin/sh Bundan sonra yıllarca Bourne kabuğu (veya BSK'lar için ücretsiz bir yeniden uygulama olan Almquist kabuğu).

Günümüzde, /bin/shdaha çok shksh88 dilinin (ve bazı uyumsuzluklarla Bourne kabuk diline ait bir süpersetin) alt kümesine dayanan POSIX dili için bir tercüman veya başka bir dildir.

Bourne kabuğu veya POSIX sh dil özelliği, dizileri desteklemiyor. Ya da daha doğrusu sadece tek dizi var: konumsal parametreler ( $1, $2, $@, işlevi başına bir dizide bu kadar sıra).

ksh88 ayarladığınız dizilere sahipti set -A, ancak sözdizimi garip ve çok kullanışsız olduğu için POSIX sh de belirtilmemiş.

Dizi / listeleri değişkenlerle diğer kabukları içerir: csh/ tcsh, rc, es, bash(çoğunlukla Ksh sözdizimini ksh93 şekilde kopyalanır olan), yash, zsh, fishfarklı sözdizimi (her rcUnix için sözde bir kez halefi kabuk, fishve zshen tutarlı olmak olanlar) ...

Standart olarak sh(Bourne kabuğunun modern versiyonlarında da çalışır):

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)

(Bourne kabuğunda ve ksh88'de, düzgün çalışması $IFSiçin boşluk karakterini içermesi gerektiğini unutmayın "$@"(bir hata) ve Bourne kabuğunda, yukarıdaki öğelere erişemezsiniz $9( ${10}işe yaramaz, hala yapabilir shift 1; echo "$9"ya da tekrar onları)).


2
Bir ton teşekkürler ... detaylı açıklamanız çok yardımcı oldu.
SubhasisM

1
Konum parametrelerinin bazı temel özelliklerde bash dizilerinden farklı olduğunu belirtmek faydalı olabilir. Örneğin, seyrek dizileri desteklemiyorlar ve sh'in dilimleme parametresi genişlemesi olmadığından, gibi alt listelere erişemezsiniz "${@:2:4}". Elbette benzerlikleri görüyorum ama konumsal parametreleri kendi başına bir dizi olarak görmüyorum .
kojiro

@kojiro, bir ölçüde, bunu, aksine derim "$@"bir dizi gibi davranır (dizileri gibi csh, rc, zsh, fish, yash, daha var ...) Korn / bash gerçekten diziler değiliz "diziler", ancak bazı pozitif tamsayılarla sınırlı tuşları olan birleşik diziler biçimi (ayrıca diziler ve "$ @" ile diğer tüm kabuklardaki gibi 1 yerine 0'dan başlayan göstergeleri vardır). Dilimleme desteği olan kabukları $ @ dilimini aynı şekilde dilimleyebilir (ksh93 / bash ile "$ @" dilimleyince konumsal parametrelere $ 0 eklenir).
Stéphane Chazelas 23:17

3

Bourne kabuğunda sade diziler yoktur. Bir dizi oluşturmak ve onu geçmek için aşağıdaki yolu kullanabilirsiniz:

#!/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

Dizileri ne şekilde kullanırsanız kullanın sh, her zaman hantal olacaktır. Çok sınırlı bir platformla sıkışıp kalmazsanız ya da bir şeyler öğrenmek istemediğiniz sürece , Pythonya Perlda yapabileceğiniz gibi farklı bir dil kullanmayı düşünün .


Yanıtınız için teşekkürler ... !! Aslında ben gerçekten kabuk betiğinde bir şeyler öğrenmeye çalışıyorum ... aksi takdirde Python'da dizi uygulamak gerçekten çok kolay. Bu, diziyi desteklemeyen bir komut dosyası dili olan büyük bir dersti :) Bir şey, gönderdiğiniz kod bir hata veriyor - "6. satırdaki sözdizimi hatası:` $ 'beklenmedik "... Biraz meşgulüm şimdi, onu çözerdim ... plz rahatsız etmeyin.
SubhasisM

@NoobGeek, Bourne kabuğunun $(...)sözdizimi yok. Yani gerçekten Bourne kabuğuna sahip olmalısınız. Solaris 10'da veya daha önce misiniz? Muhtemelen seqikisine de sahip olmayacaksın . Solaris 10 ve önceki sürümlerinde, shBourne kabuğu yerine / usr / xpg4 / bin / sh komutunun standart olmasını istersiniz . seqBu şekilde kullanmak da pek iyi değil.
Stéphane Chazelas

POSIX, $ ve `nin komut ikameinde eşdeğer olduğunu belirtir: link . Ve neden seqbu şekilde kullanmak iyi değil?
Arkadiusz Drabczyk

2
Evet POSIX kabuklarda, tercih etmelidir $(...)üzerinde `, ancak OP en /bin/shmuhtemelen Bourne kabuğu değil, bir POSIX kabuk. Yanında seqdurumu, standart bir komut olmayan $(seq 100)bellek bütün çıkış saklama araçlarında ve araçlarının bu yeni satır içeren $ IFS mevcut değerine bağlı olan ve basamak içeren değildir. Kullanımı en iyisi i=1; while [ "$i" -le 100 ]; ...; i=$(($i + 1)); done(ancak bu Bourne kabuğunda da işe yaramaz).
Stéphane Chazelas

1
@Daenyth, ben tam tersini söylemek isterim: önce temelleri öğrenmek, sonra da taşınabilir /bin/shsözdizimini sonra öğrenmek, insanların yanlış #!/bin/shshebang kullanmanın uygun olduğunu düşünmesini sağlama eğilimindedir ve daha sonra diğer insanlar bunları kullanmayı denediğinde senaryolarını kırar. Bu tür flamebait göndermemeniz tavsiye edilir. :)
Josip Rodin

2

Diğerlerinin de dediği gibi, Bourne Kabuğu'nun gerçek dizileri yoktur.

Ancak, yapmanız gerekenlere bağlı olarak, sınırlandırılmış dizeler yeterli olacaktır:

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

Tipik sınırlayıcılar (boşluk, sekme ve yeni satır) yeterli olmazsa IFS, döngüden önce istediğiniz sınırlayıcıyı ayarlayabilirsiniz .

Diziyi programlı olarak oluşturmanız gerekirse, sınırlandırılmış bir dize oluşturabilirsiniz.


1
İstemediğiniz sürece (muhtemel olmayan), muhtemelen değişkenleri bırakmanın başka bir etkisi olan globbing'i de devre dışı bırakmak isteyeceksinizdir ( split+globoperatör).
Stéphane Chazelas 13:15

0

Çizgi benzetmek diziler için bir yol (bir dizinin boyutları herhangi bir sayı için adapte edilebilir) (Not: kullanımı Lütfen, seqkomut gerektirir IFS. (BOŞLUK varsayılan değer = ')' a ayarlanır kullanabilirsiniz while ... do ...veya do ... while ...Bundan kaçınmak için döngüler ( seqkodun ne yaptığını daha iyi bir örnek kapsamında tuttum ).

#!/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
Bu süre Not localikisi tarafından destekleniyor bashve dashbu POSIX değildir. seqPOSIX komutu da değil. Muhtemelen kodunuzun $ IFS'nin şu anki değeri hakkında bazı varsayımlarda bulunduğundan bahsetmelisiniz ( seqdeğişkenlerinizi kullanmaktan kaçınırsanız , kaçınılabilir)
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.