Bash'da $ # ne demektir?

17

Örnek adında bir dosyada bir komut dosyası var:

echo "hello world"
echo 

Ve bu betiği kullanarak çalıştırdığımda:

./instance solfish

Bu çıkışı aldım:

hello world
solfish

Ama koştuğumda:

echo $# 

"0" yazıyor. Niye ya? % Co_de% değerinin ne anlama geldiğini anlamıyorum.

Lütfen açıkla.

    
sordu solfish 25.07.2017 16:26

4 cevap

57

$# , bash değerindeki özel bir değişkendir, bu da argümanların sayısına (konumsal parametreler), yani söz konusu betiğe , ... geçirilen veya argümanın doğrudan kabuğa geçmesi durumunda kabuk, örn. bash -c '...' .... .

Bu, C'deki% co_de yüzdesine benzer.

Belki de bu açıklığa kavuşacaktır:

$ bash -c 'echo $#'
0

$ bash -c 'echo $#' _ x
1

$ bash -c 'echo $#' _ x y
2

$ bash -c 'echo $#' _ x y z
3

Dikkat edin, argc , 0'dan başlayarak onu takip eden komuttan sonra argüman alır ( bash -c ; teknik olarak, bash 'in _ ' sini ayarlamanıza izin vermenin bir yolu, gerçekten bir argüman değil), bu yüzden x , burada bir yer tutucu olarak kullanılır; gerçek argümanlar ( y ), ( z ) ve ( script.sh ).

Benzer şekilde, komut dosyanızda ( %code% varsayarak):

#!/usr/bin/env bash
echo "$#"

Sonra yaptığınız zaman:

./script.sh foo bar

komut dosyası 2 çıktı olacak; Benzer şekilde,

./script.sh foo

1 çıktı.

    
verilen cevap heemayl 25.07.2017 16:39
16

echo $# , komut dosyanızın konumsal parametrelerinin sayısını çıkarır.

Hiçbiriniz yok, bu yüzden 0 çıktı.

echo $# , betik içinde ayrı bir komut olarak değil, yararlıdır.

gibi bazı parametreler içeren bir komut dosyası çalıştırırsanız
./instance par1 par2

Komut dosyasına yerleştirilen echo $# değeri 2 olacak.

    
verilen cevap Pilot6 25.07.2017 16:29
12

$# , bir parametrenin geçtiğinden emin olmak için genellikle bash betiklerinde kullanılır. Genellikle komut dosyanızın başında bir parametre olup olmadığını kontrol edersiniz.

Örneğin, bugün üzerinde çalıştığım bir komut dosyasının bir pasajı:

if [[ $# -ne 1 ]]; then
    echo 'One argument required for file name, e.g. "Backup-2017-07-25"'
    echo '.tar will automatically be added as a file extension'
    exit 1
fi

Özetlemek için $# , bir komut dosyasına geçirilen parametre sayısını bildirir. Durumunuzda hiçbir parametre geçmediniz ve bildirilen sonuç 0 .

Diğer # , Bash'de kullanılıyor

# değeri, olayların sayısını veya bir değişkenin uzunluğunu saymak için genellikle bash olarak kullanılır.

Bir dizenin uzunluğunu bulmak için:

myvar="some string"; echo ${#myvar}

şunu döndürür: 11

Dizi öğelerinin sayısını bulmak için:

myArr=(A B C); echo ${#myArr[@]}

şunu döndürür: 3

İlk dizi öğesinin uzunluğunu bulmak için:

myArr=(A B C); echo ${#myArr[0]}

şunu döndürür: 1 ( A 'nin uzunluğu, 0 dizinin sıfır temelli indis / subscripts kullanmasıyla ilk elementtir).

    
verilen cevap WinEunuuchs2Unix 25.07.2017 16:44
9

$# argüman sayısıdır, ancak bir işlevde farklı olacağını unutmayın.

$# , komut dosyasına geçirilen konumsal parametrelerin sayısı, kabuk, veya kabuk işlevi . Bunun nedeni, bir kabuk işlevi çalışırken, konumsal parametreler geçici olarak argümanlarla değiştirilir. işlevine. Bu, işlevlerin kendi konumsal parametrelerini kabul etmesini ve kullanmasını sağlar.

Bu komut dosyası, komut dosyasının kendisine kaç tane argümanın aktarıldığına bakılmaksızın her zaman 3 yazdırır, çünkü "$#" işlevindeki f işlevi, işleve iletilen argümanların sayısına doğru genişler:

#!/bin/sh

f() {
    echo "$#"
}

f a b c

Bu önemli çünkü konumsal parametrelerin kabuk işlevlerinde nasıl çalıştığını bilmiyorsanız, böyle bir kodun beklediğiniz gibi çalışmadığı anlamına gelir:

#!/bin/sh

check_args() { # doesn't work!
    if [ "$#" -ne 2 ]; then
        printf '%s: error: need 2 arguments, got %d\n' "
#!/bin/sh

check_args() { # works -- the caller must pass the number of arguments received
    if [ "" -ne 2 ]; then
        printf '%s: error: need 2 arguments, got %d\n' "
$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3
" "" >&2 exit 1 fi } # Maybe check some other things... check_args "$#"
" "$#" >&2 exit 1 fi } # Maybe check some other things... check_args # Do other stuff...

check_args , $# işlevi, kendisine gönderilen argümanların sayısına doğru genişler ve bu betikte her zaman 0 olur.

Bir kabuk işlevinde bu tür bir işlev istiyorsanız, bunun gibi bir şey yazmanız gerekir:

#!/bin/sh

outer() {
    inner() {
        printf 'inner() got %d arguments\n' "$#"
    }

    printf 'outer() got %d arguments\n' "$#"
    inner x y z
}

printf 'script got %d arguments\n' "$#"
outer p q

Bu, $# işlevinin dışında işlevi ve konumsal parametrelerinden biri olarak işleve iletilmesi nedeniyle çalışır. İşlev içinde , parçası olduğu betiğe değil, kabuk işlevine iletilen ilk konumsal parametreye genişler.

Böylece, $# gibi, , vb. gibi özel parametreler, [email protected] ve $* gibi parametreler de, bir işleve iletilen argümanlarla ilgilidir. işlev. Bununla birlikte, nested işlevi işlevinin adına çevirmiyor, bu yüzden hala kaliteli bir hata mesajı üretmek için kullanabildim.

$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments

Benzer şekilde, bir işlevi diğerinin içinde tanımlarsanız, genişletmenin gerçekleştirildiği en içteki işleve iletilen konumsal parametrelerle çalışıyorsunuz:

#!/bin/sh

while [ "$#"  -ne 0 ]; do
    printf '%d argument(s) remaining.\nGot "%s".\n\n' "$#" ""
    shift
done

Bu komut dosyasını chmod +x nested olarak çağırdım ve ( shift çalıştırdıktan sonra) çalıştırdım:

$ ./do-shift foo bar baz      # I named the script do-shift.
3 argument(s) remaining.
Got "foo".

2 argument(s) remaining.
Got "bar".

1 argument(s) remaining.
Got "baz".

Evet, biliyorum. "1 argüman" çoğullama hatasıdır.

Konumsal parametreler de değiştirilebilir.

Bir komut dosyası yazıyorsanız, bir fonksiyonun dışındaki konumsal parametreler, komut satırına değiştirmediğiniz sürece komut satırı argümanları olacaktır .

.

Bunları değiştirmenin yaygın bir yolu,% konum_adı% yerleşkesidir; bu, her bir konumsal parametreyi sola kaydırır, ilkini bırakır ve $# 'yi 1:

azaltır.
#!/bin/sh

printf '%d args: %s\n' "$#" "$*"
set foo bar baz
printf '%d args: %s\n' "$#" "$*"
$ ./set-args a b c d e      # I named the script set-args.
5 args: a b c d e
3 args: foo bar baz

Ayrıca, set builtin ile de değiştirilebilirler:

%pre% %pre%     
verilen cevap Eliah Kagan 25.07.2017 21:17

Etiketlerdeki diğer soruları oku