Bir Bash betiğine verilen argümanlar konumsal parametrelerde saklanır: ilk argüman $1, ikincisi $2, onuncusu ${10} ile okunur. $# argüman sayısını, "$@" bütün argümanları ayrı ayrı, "$*" ise hepsini tek bir metin olarak verir. $0 betiğin adını, $? son komutun çıkış durumunu, $$ kabuğun süreç numarasını, $! son arka plan işinin süreç numarasını tutar.
Bu yazıda kılavuzun konumsal ve özel parametreler bölümünü örneklerle açıyor, "$@" ile "$*" arasındaki farkı, shift ve set -- ile argüman listesini değiştirmeyi ve küçük bir seçenek ayrıştırıcı yazmayı gösteriyoruz. Örneklerin çoğunda argümanları set -- ile veriyoruz; bu, betiği farklı argümanlarla tekrar tekrar çağırmadan aynı sonucu görmenizi sağlar. Serinin geri kalanı için Bash öğrenme rehberi sayfasına bakabilirsiniz.
Konumsal parametreler: $1, $2, ${10}
Kılavuza göre konumsal parametre, 0 dışındaki bir veya daha fazla rakamla gösterilen parametredir. Kabuk başlatılırken argümanlardan atanır, set komutuyla yeniden atanabilir, ama 1=deger gibi bir atama ifadesiyle değiştirilemez. Aşağıdaki betiği goster.sh adıyla kaydedip iki argümanla çalıştırın; ikinci argüman tırnak içinde olduğu için boşluğuna rağmen tek bir argümandır:
#!/usr/bin/env bash
echo "betik: $0"
echo "argüman sayısı: $#"
echo "birinci: $1"
echo "ikinci: $2"
echo "hepsi: $*"$ bash goster.sh elma "kırmızı armut"
betik: goster.sh
argüman sayısı: 2
birinci: elma
ikinci: kırmızı armut
hepsi: elma kırmızı armutBirden fazla rakamdan oluşan konumsal parametreler süslü parantezle yazılmalıdır. Kılavuz, parantez olmadan dolar işaretinden sonraki rakamın yalnızca ilk dokuz parametreye veya $0 değerine karşılık gelebileceğini belirtir. $10 yazdığınızda kabuk $1 değerinin arkasına bir sıfır ekler:
set -- a b c d e f g h i j k
echo "$10 ${10} ${11}"
# çıktı: a0 j k
echo "$#"
# çıktı: 11"$@" ile "$*" arasındaki fark
İkisi de bütün konumsal parametreleri birinciden başlayarak verir; fark çift tırnak içinde ortaya çıkar. Kılavuza göre "$@", "$1" "$2" ... ile eşdeğerdir: her parametre ayrı bir kelime olarak korunur. "$*" ise "$1c$2c..." ile eşdeğerdir; yani bütün parametreler tek bir kelimede, IFS değişkeninin ilk karakteriyle birleştirilir. IFS tanımsızsa ayırıcı boşluk, boşsa hiçbir ayırıcı kullanılmaz. Tırnaksız $@ ve $* ise kelime bölme ve dosya adı genişletmesinden geçer:
say() { echo "$# argüman"; }
set -- "bir iki" üç
say "$@"
# çıktı: 2 argüman
say "$*"
# çıktı: 1 argüman
say $@
# çıktı: 3 argüman
say $*
# çıktı: 3 argüman
IFS=,
echo "$*"
# çıktı: bir iki,üç
unset IFS
echo "$*"
# çıktı: bir iki üçBu yüzden argümanları başka bir komuta veya fonksiyona olduğu gibi aktarırken neredeyse her zaman "$@" yazılır. Tırnaksız $@, "bir iki" argümanını iki parçaya ayırdı ve üç argüman üretti. "$*" ise argümanları bir günlük satırında veya bir mesajda tek metin olarak göstermek istediğinizde kullanışlıdır.
Kılavuzda iki ayrıntı daha geçer. Konumsal parametre yoksa "$@" ve $@ hiçbir şeye genişlemez, yani tamamen kaybolur; "$*" ise tek bir boş argüman üretir. Ayrıca "$@" bir kelimenin içinde geçiyorsa ilk parametre kelimenin başındaki metinle, son parametre sonundaki metinle birleşir:
say() { echo "$# argüman"; }
set --
say "$@"
# çıktı: 0 argüman
say "$*"
# çıktı: 1 argüman
set -- a b c
printf '[%s]\n' "ön-$@-son"
# çıktı:
# [ön-a]
# [b]
# [c-son]Argümanların bir kısmını almak için dizi dilimleme sözdizimi konumsal parametrelerde de çalışır: "${@:2}" ikinciden başlayarak hepsini, "${@:2:3}" ikinciden başlayarak üç tanesini, "${@: -1}" ise sonuncuyu verir. Eksi sayıdan önceki boşluk, ifadenin ${@:-varsayılan} ile karışmasını önler:
set -- a b c d e
echo "${@:2}"
# çıktı: b c d e
echo "${@:2:3}"
# çıktı: b c d
echo "${@: -1}"
# çıktı: eÖzel parametreler: $#, $?, $$, $!, $-, $0

Kılavuz bazı parametreleri özel olarak işler; bunlar yalnızca okunabilir, onlara atama yapılamaz. $# konumsal parametre sayısını onluk tabanda verir. $? en son çalışan komutun çıkış durumudur ve her komuttan sonra değiştiği için değerini hemen bir değişkene almak iyi bir alışkanlıktır. $- o anda açık olan kabuk seçeneklerinin harflerini gösterir; set -u açıldığında listeye u harfi eklenir:
false
echo "$?"
# çıktı: 1
echo "$?"
# çıktı: 0
echo "$-"
# çıktı: hB
set -u
echo "$-"
# çıktı: huBİkinci echo "$?" satırı 0 yazdı, çünkü bu kez $?, bir önceki echo komutunun başarılı durumunu gösteriyordu. $- çıktısındaki h ve B, varsayılan olarak açık olan hashall ve braceexpand seçeneklerine karşılık gelir; seçenekler set -euo pipefail yazısında anlatılıyor.
$$ kabuğun süreç numarasını verir. Kılavuza göre bir alt kabukta bile alt kabuğun değil, onu başlatan kabuğun numarasını gösterir; o anki sürecin gerçek numarası gerekiyorsa BASHPID değişkeni kullanılır. $! ise arka plana gönderilen son işin süreç numarasıdır ve wait ile o işin bitmesini beklemek için kullanılır. Süreç numaraları her çalıştırmada değiştiği için örnekte yalnızca sayı olup olmadıklarını denetliyoruz:
[[ $$ =~ ^[0-9]+$ ]] && echo '$$ bir sayı'
# çıktı: $$ bir sayı
ana=$$
( [[ $$ == "$ana" ]] && echo 'alt kabukta $$ aynı' )
# çıktı: alt kabukta $$ aynı
( [[ $BASHPID != "$ana" ]] && echo 'alt kabukta BASHPID farklı' )
# çıktı: alt kabukta BASHPID farklı
sleep 1 &
[[ $! =~ ^[0-9]+$ ]] && echo '$! bir sayı'
# çıktı: $! bir sayı
wait $!
echo "arka plan işi bitti, durum: $?"
# çıktı: arka plan işi bitti, durum: 0$0 kabuğun veya betiğin adıdır. Bir betik dosyası çalıştırıldığında dosyanın adı, bash -c ile çalıştırıldığında komut dizgesinden sonraki ilk argüman olur. Fonksiyon içinde konumsal parametreler fonksiyonun argümanlarıyla geçici olarak değiştirilir, ama $0 değişmez:
f() { echo "fonksiyon: 0=$0 1=$1 #=$#"; }
set -- dış1 dış2
f iç
# çıktı: fonksiyon: 0=ornek.sh 1=iç #=1
echo "dışarıda: 1=$1 #=$#"
# çıktı: dışarıda: 1=dış1 #=2Fonksiyon döndüğünde konumsal parametreler eski değerlerine kavuştu. Fonksiyonların argüman alması fonksiyon yazısında, çıkış durumlarının anlamı exit kodları yazısında, arka plan işleri ise jobs, fg, bg yazısında anlatılıyor.
| Parametre | Anlamı |
|---|---|
| $1 ... $9, ${10} | Konumsal parametreler |
| $# | Konumsal parametre sayısı |
| "$@" | Her parametre ayrı kelime |
| "$*" | Tüm parametreler tek kelime, IFS ilk karakteriyle birleşik |
| $? | Son komutun çıkış durumu |
| $$ | Kabuğun süreç numarası (alt kabukta da aynı) |
| $! | Son arka plan işinin süreç numarası |
| $- | Açık kabuk seçeneklerinin harfleri |
| $0 | Kabuğun veya betiğin adı |
Argümanlar üzerinde döngü

Bütün argümanları sırayla işlemenin en açık yolu for arg in "$@" döngüsüdür. Kılavuz, for komutunda in kısmı yazılmazsa döngünün tanımlı her konumsal parametre için, yani in "$@" yazılmış gibi çalıştığını belirtir. Bu yüzden for arg; do biçimi aynı işi daha kısa yazar. Argümanları sonradan tekrar kullanmak veya listeyi değiştirmeden dolaşmak istiyorsanız, onları bir diziye kopyalamak iyi bir yöntemdir; "$@" tırnaklı yazıldığı için her argüman dizinin ayrı bir elemanı olur:
set -- "ilk dosya" ikinci
for arg; do
echo "[$arg]"
done
# çıktı:
# [ilk dosya]
# [ikinci]
argumanlar=("$@")
echo "${#argumanlar[@]} eleman, ilki: ${argumanlar[0]}"
# çıktı: 2 eleman, ilki: ilk dosyaDizi kopyası, shift ile listeyi tükettikten sonra bile özgün argümanlara erişmenizi sağlar. Dizinin dilimlenmesi ve eleman eklenmesi dizi yazısında, for döngüsünün diğer biçimleri ise for döngüsü yazısında anlatılıyor.
Argüman sayısını denetlemek
Bir betiğin beklediği argümanlar verilmediğinde sessizce yanlış bir iş yapması yerine kullanım mesajı gösterip durması daha güvenlidir. $# değerini aritmetik bir karşılaştırmayla denetleyebilir, mesajı standart hataya yazıp kullanım hatalarında yaygın olarak kullanılan 2 durum koduyla çıkabilirsiniz. Kılavuz da yerleşik komutların yanlış kullanımda, örneğin eksik argüman veya geçersiz seçenekte, 2 döndürdüğünü belirtir. Aşağıdaki örnek bir fonksiyon içinde aynı denetimi yapıyor:
kopyala() {
if (( $# != 2 )); then
echo "Kullanım: kopyala <kaynak> <hedef>" >&2
return 2
fi
echo "$1 dosyası $2 olarak kopyalanacak"
}
kopyala tek 2>&1
# çıktı: Kullanım: kopyala <kaynak> <hedef>
# $? = 2
kopyala a.txt b.txt
# çıktı: a.txt dosyası b.txt olarak kopyalanacakÖrnekte hata mesajını görebilmeniz için 2>&1 ile standart hatayı standart çıktıya yönlendirdik. Betiğin en üst düzeyinde aynı denetimi return yerine exit ile yaparsınız. Değeri boş olan ama verilmiş bir argümanı ("") yakalamak isterseniz sayıya ek olarak [[ -z $1 ]] gibi bir test de gerekir, çünkü boş argüman da $# değerine sayılır.
shift: argümanları sola kaydırmak
shift n, konumsal parametreleri n kadar sola kaydırır: n+1 numaralı parametre $1 olur ve en sondaki n parametre silinir. n verilmezse 1 kabul edilir. Kılavuza göre n sıfırsa veya $# değerinden büyükse parametreler değişmez ve n fazla büyükse komut sıfırdan farklı bir durumla döner. Bu yüzden argüman sayısını denetlemeden shift 2 yazmak sessizce hiçbir şey yapmayabilir:
set -- -v dosya1 dosya2
echo "ilk: $1"
# çıktı: ilk: -v
shift
echo "şimdi: $1, kalan: $#"
# çıktı: şimdi: dosya1, kalan: 2
shift 5
echo "durum: $?, kalan: $#"
# çıktı: durum: 1, kalan: 2
while (( $# > 0 )); do
echo "işleniyor: $1"
shift
done
# çıktı:
# işleniyor: dosya1
# işleniyor: dosya2POSIX modunda shift_verbose seçeneği açılır ve parametre sayısını aşan shift bir hata mesajı yazar. Varsayılan modda mesaj yoktur, yalnızca çıkış durumu başarısızlığı gösterir.
set -- ile argüman listesini değiştirmek
set komutunda seçeneklerden sonra kalan argümanlar konumsal parametrelerin yerini alır. -- seçeneğinden sonra argüman yoksa konumsal parametreler silinir; varsa, bazıları tire ile başlasa bile parametrelere atanır. Bu sayede listeyi baştan kurabilir, sonuna eleman ekleyebilir veya tamamen boşaltabilirsiniz:
set -- bir iki
set -- "$@" üç
echo "$# : $*"
# çıktı: 3 : bir iki üç
set -- -x --yardim
echo "$1 $2"
# çıktı: -x --yardim
set --
echo "kalan: $#"
# çıktı: kalan: 0set -- -x satırında -- olmasaydı set, -x argümanını izleme seçeneği olarak yorumlar ve kabuğun ayarını değiştirirdi. Kullanıcıdan gelen değerleri set ile konumsal parametrelere atarken bu yüzden her zaman -- yazın.
Argümanları başka bir komuta aktarmak
Sarmalayıcı (wrapper) fonksiyonlar ve betikler, kendilerine gelen argümanları değiştirmeden başka bir komuta iletir. Bu işin doğru yazımı "$@" biçimidir; aynı argümanları bir günlük satırında okunabilir biçimde göstermek için ise "$*" uygundur. Aşağıdaki fonksiyon, çalıştıracağı komutu önce tek satırda yazıyor, ardından argümanları hiç bölmeden çalıştırıyor:
gunluk() {
printf '[günlük] %s\n' "$*"
"$@"
}
gunluk printf '%s|' "a b" c; echo
# çıktı:
# [günlük] printf %s| a b c
# a b|c|Günlük satırında "a b" ile "c" ayrımı görünmüyor, çünkü "$*" argümanları boşlukla birleştirdi. Çalıştırma sırasında ise "$@" sayesinde printf komutu "a b" değerini tek argüman olarak aldı. Günlükte argüman sınırlarının da görünmesini isterseniz printf '%q ' ile her argümanı ayrı ayrı tırnaklayarak yazabilirsiniz; bu yöntem echo ve printf yazısında anlatılıyor.
$0 değerini değiştirmeniz gerekirse, örneğin hata mesajlarında betiğin kısa adını göstermek için, Bash'in BASH_ARGV0 değişkeni kullanılabilir. Kılavuza göre bu değişken okunduğunda $0 ile aynı değeri verir, ona atama yapmak ise $0 değerini de değiştirir. Değişken unset ile silinirse özel davranışını kaybeder.
Uygulama: küçük bir seçenek ayrıştırıcı
Basit betiklerde seçenekleri while, case ve shift üçlüsüyle ayrıştırmak yeterlidir. Aşağıdaki örnek -v bayrağını, değer alan -o seçeneğini ve seçeneklerin bittiğini gösteren -- işaretini tanır; seçenek olmayan ilk argümanda durur ve kalan argümanları dosya listesi olarak kullanır:
set -- -v -o rapor.txt girdi1 "girdi 2"
ayrintili=0
cikti=""
while (( $# > 0 )); do
case $1 in
-v) ayrintili=1; shift ;;
-o) cikti=${2:?-o bir değer ister}; shift 2 ;;
--) shift; break ;;
-*) echo "bilinmeyen seçenek: $1" >&2; exit 2 ;;
*) break ;;
esac
done
echo "ayrıntılı=$ayrintili çıktı=$cikti"
# çıktı: ayrıntılı=1 çıktı=rapor.txt
printf 'dosya: %s\n' "$@"
# çıktı:
# dosya: girdi1
# dosya: girdi 2-o dalındaki ${2:?mesaj} genişletmesi, değer eksikse betiği bir hata mesajıyla durdurur; bu biçim varsayılan değer yazısında anlatılıyor. Döngü bittiğinde konumsal parametrelerde yalnızca dosya adları kalır ve "$@" onları boşluklarını koruyarak verir. -vo dosya gibi birleşik seçenekleri desteklemek veya hata mesajlarını standartlaştırmak istediğinizde yerleşik getopts komutu daha uygundur; getopts yazısında ayrıntılı anlatılıyor.
Sık yapılan hatalar

- $10 yazmak:
$10,$1ve ardından gelen bir sıfırdır.${10}yazın. - Argümanları tırnaksız aktarmak:
komut $@boşluk içeren argümanları böler;komut "$@"yazın. - $? değerini geç okumak: Araya giren her komut,
echobile,$?değerini değiştirir.durum=$?ile hemen saklayın. - shift sonucunu denetlememek: Yeterli argüman yoksa
shift 2hiçbir şey yapmaz ve döngü sonsuza kadar dönebilir. - set ile tire içeren değerler atamak:
set $degerdeğer tireyle başlıyorsa seçenek sayılır;set -- "$deger"yazın. - $$ değerini alt kabuğun numarası sanmak: Alt kabukta
$$değişmez; gerçek süreç numarası içinBASHPIDkullanın.
Sık Sorulan Sorular
Bash betiğine kaç argüman verildiğini nasıl öğrenirim?
$# özel parametresi konumsal parametre sayısını verir. Betiğin başında (( $# >= 1 )) || { echo "Kullanım: $0 dosya" >&2; exit 2; } gibi bir denetimle eksik argümanda kullanım mesajı gösterebilirsiniz.
$@ ile $* arasındaki fark nedir?
Tırnaksız kullanıldıklarında aynı davranırlar. Çift tırnak içinde "$@" her argümanı ayrı bir kelime olarak korur, "$*" ise hepsini IFS değişkeninin ilk karakteriyle birleştirip tek bir kelime yapar.
Argümanları virgülle birleştirip tek metin yapabilir miyim?
Evet. "$*", argümanları IFS değişkeninin ilk karakteriyle birleştirir. Kabuğun genel IFS değerini bozmamak için işlemi bir fonksiyonda local IFS=, ile yapın ya da bir alt kabukta çalıştırın: liste=$(IFS=,; echo "$*"). Birden fazla karakterlik bir ayırıcı gerekiyorsa printf ile her argümandan sonra ayırıcı yazıp sondakini kırpabilirsiniz.
Betiğe 9'dan fazla argüman verebilir miyim?
Evet; argüman sayısı için kılavuzda dokuz gibi bir sınır yoktur. Sınır yalnızca yazımdadır: onuncu ve sonraki argümanlar ${10}, ${11} biçiminde süslü parantezle okunur. Çok sayıda argümanı tek tek numarayla okumak yerine for arg; do döngüsü veya shift kullanmak daha okunaklıdır.
Son argümana nasıl erişirim?
"${@: -1}" son konumsal parametreyi verir. Eksi işaretinden önceki boşluk gereklidir; boşluk olmazsa ifade varsayılan değer genişletmesi olarak yorumlanır.
Betik içinde argüman listesini değiştirebilir miyim?
Evet. set -- yeni argümanlar listeyi baştan kurar, set -- "$@" ek sona ekler, shift baştan siler. Konumsal parametrelere 1=deger biçiminde doğrudan atama yapılamaz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Bash öğrenme rehberi · Script yazma · getopts · for döngüsü · Fonksiyonlar