getopts, Bash betiklerinde -v, -o dosya gibi kısa seçenekleri ayrıştırmak için kullanılan yerleşik komuttur. Genellikle bir while döngüsü ve case ile birlikte yazılır: while getopts "vo:" secenek; do case $secenek in ... esac; done. Seçenek dizesindeki her harf bir seçeneği, harfin arkasındaki iki nokta o seçeneğin bir değer aldığını gösterir. Değer OPTARG değişkenine, sıradaki argümanın konumu OPTIND değişkenine yazılır; döngüden sonra shift $(( OPTIND - 1 )) ile seçenekler atılır ve geriye kalan argümanlar "$@" içinde kalır.
Bu yazıda getopts komutunun kılavuzdaki kurallarını, iki hata bildirme modunu, OPTIND değişkeninin neden elle sıfırlanması gerektiğini, birleşik seçenekleri ve eksiksiz bir kullanım mesajı şablonunu GNU Bash 5.2.37 ile çalıştırılmış örneklerle anlatıyoruz. Konumsal parametrelerin ($1, $#, shift) temeli için Bash script argümanları ve özel değişkenler yazısını, tüm öğrenme yolu için Bash öğrenme rehberi sayfasını okuyabilirsiniz.
getopts nasıl çalışır

Kılavuzdaki biçim getopts seçenek_dizesi ad [argüman ...] şeklindedir. Her çağrıda getopts sıradaki seçeneği bulur, harfini ad olarak verdiğiniz değişkene yazar (değişken yoksa oluşturur) ve işlenecek sonraki argümanın sırasını OPTIND değişkenine kaydeder. Seçenek bir değer gerektiriyorsa bu değer OPTARG değişkenine konur. Bir seçenek bulunduğunda getopts başarı (0) döndürür; seçenekler bittiğinde ya da hata olduğunda sıfırdan büyük bir değer döndürür ve döngü sona erer.
Seçenek dizesinde iki karakterin özel anlamı vardır: iki nokta (:) ve soru işareti (?) seçenek harfi olarak kullanılamaz. Kılavuz, değer alan seçeneklerde değerin seçenekten boşlukla ayrılmasını bekler. OPTIND, kabuk ya da betik her başlatıldığında 1 değerini alır. Aşağıdaki küçük betik, her adımda değişkenlerin nasıl değiştiğini gösterir.
while getopts "vo:" s; do
echo "s=$s OPTARG=${OPTARG-} OPTIND=$OPTIND"
done
echo "döngü sonu: s=$s OPTIND=$OPTIND"# iz.sh dosyasını farklı argümanlarla çağırıyoruz
bash iz.sh -v -o arsiv.tar belgeler
# çıktı: s=v OPTARG= OPTIND=2
# çıktı: s=o OPTARG=arsiv.tar OPTIND=4
# çıktı: döngü sonu: s=? OPTIND=4İlk turda -v bulundu ve OPTIND 2 oldu, yani sıradaki argüman ikinci sırada. İkinci turda -o ve değeri arsiv.tar birlikte tüketildi, bu yüzden OPTIND doğrudan 4'e atladı. Üçüncü çağrıda belgeler bir seçenek olmadığı için getopts durdu. Kılavuzun anlattığı gibi seçenekler bittiğinde ad değişkenine ? yazılır ve OPTIND ilk seçenek olmayan argümanın sırasını gösterir. shift $(( OPTIND - 1 )) ifadesinin mantığı buradan gelir: 4 - 1 = 3 argüman atılınca $1 artık belgeler olur.
Tam bir örnek: while, case ve shift
Gerçek bir betikte seçenekleri değişkenlere aktarır, döngüden sonra kalan argümanları ayrıca işlersiniz. Aşağıdaki yedekle.sh, -v ile ayrıntılı modu açar, -o ile çıktı dosyasının adını alır ve geriye kalan her argümanı bir kaynak olarak kabul eder. Bu betik bir şey yedeklemiyor, yalnızca ayrıştırmanın sonucunu yazdırıyor.
#!/usr/bin/env bash
# yedekle.sh
ayrintili=0
cikti="./yedek.tar"
while getopts "vo:" secenek; do
case $secenek in
v) ayrintili=1 ;;
o) cikti=$OPTARG ;;
*) exit 2 ;;
esac
done
shift $(( OPTIND - 1 ))
echo "ayrıntılı: $ayrintili, çıktı: $cikti, kaynaklar: $*"bash yedekle.sh -v -o ./arsiv.tar belgeler resimler
# çıktı: ayrıntılı: 1, çıktı: ./arsiv.tar, kaynaklar: belgeler resimler
bash yedekle.sh belgeler
# çıktı: ayrıntılı: 0, çıktı: ./yedek.tar, kaynaklar: belgeler
bash yedekle.sh -vo ./b.tar notlar
# çıktı: ayrıntılı: 1, çıktı: ./b.tar, kaynaklar: notlar
bash yedekle.sh -o./c.tar notlar
# çıktı: ayrıntılı: 0, çıktı: ./c.tar, kaynaklar: notlarÜçüncü çağrı, değer almayan seçeneklerin birleştirilebileceğini gösterir: -vo ./b.tar, -v -o ./b.tar ile aynı sonucu verir. Dördüncü çağrıda değer seçeneğe bitişik yazıldı; kılavuz değerin boşlukla ayrılması gerektiğini söylese de Bash 5.2.37 ile denediğimizde bu yazım da kabul edildi. Taşınabilirlik için boşluklu yazımı belgeleyin. case yapısındaki desenler ve ;; sonlandırıcısı için Bash case esac kullanımı yazısına bakabilirsiniz.
Seçenek ayrıştırma nerede durur
getopts, seçenek gibi görünmeyen ilk argümanda durur; sonrasında gelen tireli argümanlar artık seçenek sayılmaz. İki tire (--) ise seçeneklerin sonunu açıkça işaretler; getopts bu işareti tüketir ve ardından gelen her şeyi sıradan argüman olarak bırakır. Bu, adı tireyle başlayan bir dosyayı argüman olarak geçmenin güvenli yoludur.
bash iz.sh belgeler -v
# çıktı: döngü sonu: s=? OPTIND=1
bash iz.sh -v -- -o
# çıktı: s=v OPTARG= OPTIND=2
# çıktı: döngü sonu: s=? OPTIND=3İlk çağrıda belgeler en başta olduğu için hiçbir seçenek işlenmedi ve -v sıradan bir argüman olarak kaldı. Kullanıcıların seçenekleri dosya adlarından sonra yazma alışkanlığı varsa bunu kullanım mesajında belirtin; getopts bu sırayı kendiliğinden düzeltmez. İkinci çağrıda OPTIND 3 oldu, yani shift sonrasında $1 değeri -o metnidir.
İki hata modu: normal ve sessiz

getopts hataları iki biçimde bildirebilir. Normal modda geçersiz bir seçenek ya da eksik bir değer gördüğünde kendisi bir tanı mesajı yazar, ad değişkenine ? koyar ve OPTARG değişkenini kaldırır. Bu modda iki hata türünü case içinde birbirinden ayıramazsınız; ikisi de ? olarak gelir.
bash iz.sh -x
bash iz.sh -o
# çıktı: iz.sh: illegal option -- x
# çıktı: s=? OPTARG= OPTIND=2
# çıktı: döngü sonu: s=? OPTIND=2
# çıktı: iz.sh: option requires an argument -- o
# çıktı: s=? OPTARG= OPTIND=2
# çıktı: döngü sonu: s=? OPTIND=2Seçenek dizesi iki noktayla başlarsa getopts sessiz moda geçer. Bu modda hiçbir mesaj yazmaz ve hataları size bırakır: geçersiz seçenekte ad değişkenine ?, OPTARG değişkenine bulunan harfi; eksik değerde ise ad değişkenine :, OPTARG değişkenine değeri eksik seçeneğin harfini yazar. Bu sayede kendi Türkçe hata mesajlarınızı üretebilirsiniz. Kılavuza göre OPTERR değişkenini 0 yapmak da mesajları kapatır, ancak bu durumda iki hata türünü ayırt etme olanağı sessiz moddaki kadar açık değildir.
while getopts ":vo:" s; do
case $s in
v) echo "ayrıntılı mod" ;;
o) echo "çıktı: $OPTARG" ;;
\?) echo "bilinmeyen seçenek: -$OPTARG" ;;
:) echo "-$OPTARG bir değer bekliyor" ;;
esac
done
# çıktı: ayrıntılı mod
# çıktı: bilinmeyen seçenek: -x
# çıktı: -o bir değer bekliyorcase içinde soru işaretini \? diye kaçırmak gerekir; aksi hâlde ? tek karakterlik herhangi bir değerle eşleşen bir joker desen olur ve v ile o dışındaki her şeyi yakalar. Joker desenler için Bash joker karakterler yazısına bakabilirsiniz.
OPTIND neden elle sıfırlanmalı
Kılavuz açıkça uyarır: kabuk OPTIND değişkenini kendiliğinden sıfırlamaz. Aynı kabuk içinde getopts komutunu yeni bir argüman kümesiyle tekrar kullanacaksanız, örneğin seçenek alan bir fonksiyonu iki kez çağırıyorsanız, OPTIND değerini her seferinde 1'e döndürmeniz gerekir. Aksi hâlde ikinci çağrı ilk çağrının bıraktığı yerden okumaya çalışır ve seçenekleri kaçırır.
hatali() {
while getopts "n:" s; do echo " isim: $OPTARG"; done
}
dogru() {
local OPTIND s
while getopts "n:" s; do echo " isim: $OPTARG"; done
}
echo "local olmadan:"
hatali -n ali
hatali -n veli
echo "local OPTIND ile:"
dogru -n ali
dogru -n veli
# çıktı: local olmadan:
# çıktı: isim: ali
# çıktı: local OPTIND ile:
# çıktı: isim: ali
# çıktı: isim: veliİlk fonksiyonun ikinci çağrısı hiçbir şey yazmadı, çünkü OPTIND önceki çağrıdan 3 değeriyle kaldı ve iki argümanlı yeni listede okunacak bir şey bulunamadı. local OPTIND değişkeni fonksiyona yerel yapar; fonksiyon bittiğinde dışarıdaki değer geri gelir ve denediğimizde her çağrı temiz başladı. Yerel değişkenlerin kapsam kuralları Bash local değişken ve kapsam yazısında. Bu kalıbı tercih etmezseniz döngüden önce OPTIND=1 yazmak da yeterlidir.
Konumsal parametreler yerine başka bir liste ayrıştırmak
getopts normalde betiğin ya da fonksiyonun konumsal parametrelerini okur. Komutun sonuna fazladan argümanlar verirseniz, onun yerine bu argümanları ayrıştırır. Bir yapılandırma dosyasından okunan ya da bir diziye toplanan seçenekleri işlemek için bu biçim kullanışlıdır.
ayarlar=(-v -o ./gunluk.tar)
while getopts "vo:" s "${ayarlar[@]}"; do
echo "seçenek: $s, değer: ${OPTARG:-yok}"
done
echo "betiğin kendi argüman sayısı: $#"
# çıktı: seçenek: v, değer: yok
# çıktı: seçenek: o, değer: ./gunluk.tar
# çıktı: betiğin kendi argüman sayısı: 0Kullanım mesajı ve zorunlu seçenekler: şablon
Aşağıdaki şablon, yazının tüm parçalarını birleştirir: sessiz hata modu, Türkçe hata mesajları, -h ile yardım, döngüden sonra zorunlu seçenek kontrolü ve kalan argümanların doğrulanması. Kılavuzun yerleşik komutlar için kullandığı geleneği izleyerek yanlış kullanımı 2 koduyla bildiriyoruz; bu kodların anlamı için Bash exit kodları yazısına bakabilirsiniz.
#!/usr/bin/env bash
set -euo pipefail
kullanim() {
cat <<EOF
kullanım: ${0##*/} -h | -k KULLANICI [-p PORT] [-v] SUNUCU...
-k bağlanılacak kullanıcı (zorunlu)
-p port (varsayılan 22)
-v ayrıntılı çıktı
EOF
}
hata() { echo "${0##*/}: $1" >&2; kullanim >&2; exit 2; }
kullanici="" port=22 ayrintili=0
while getopts ":hk:p:v" s; do
case $s in
h) kullanim; exit 0 ;;
k) kullanici=$OPTARG ;;
p) [[ $OPTARG =~ ^[0-9]+$ ]] || hata "port sayı olmalı: $OPTARG"
port=$OPTARG ;;
v) ayrintili=1 ;;
:) hata "-$OPTARG bir değer bekliyor" ;;
\?) hata "bilinmeyen seçenek: -$OPTARG" ;;
esac
done
shift $(( OPTIND - 1 ))
[[ -n $kullanici ]] || hata "-k zorunlu"
(( $# > 0 )) || hata "en az bir sunucu adı verin"
for sunucu in "$@"; do
echo "$kullanici@$sunucu port $port (ayrıntılı: $ayrintili)"
donebash baglan.sh -k deploy -p 2222 web1 web2
# çıktı: deploy@web1 port 2222 (ayrıntılı: 0)
# çıktı: deploy@web2 port 2222 (ayrıntılı: 0)
bash baglan.sh -p abc -k deploy web1
# çıktı: baglan.sh: port sayı olmalı: abc
# çıktı: kullanım: baglan.sh -h | -k KULLANICI [-p PORT] [-v] SUNUCU...
# çıktı: -k bağlanılacak kullanıcı (zorunlu)
# çıktı: -p port (varsayılan 22)
# çıktı: -v ayrıntılı çıktı
echo "durum: $?"
# çıktı: durum: 2Şablon gerçek bir bağlantı kurmuyor, yalnızca ayrıştırılan değerleri yazdırıyor; sunuculara bağlanmanın kendisi SSH ile sunucuya bağlanma yazısının konusu. ${0##*/} genişletmesi betiğin yolundan yalnızca dosya adını alır, böylece mesaj betik hangi dizinden çağrılırsa çağrılsın aynı görünür. Port kontrolündeki =~ işleci için Bash regex eşleşme, burada belgesindeki cat <<EOF kalıbı için Bash here document yazısına bakabilirsiniz.
getopts ile uzun seçenekler
Seçenek dizesi tek tek karakterlerden oluştuğu için getopts yalnızca tek harfli seçenekleri tanır; --yardim veya --port=22 gibi uzun seçenekler için bir desteği yoktur. Uzun seçenekler gerekiyorsa genellikle while (( $# > 0 )) döngüsü içinde case "$1" ve shift ile kendi ayrıştırıcınızı yazarsınız. Bu yaklaşımda seçenek birleştirme ve hata mesajları gibi işleri de sizin üstlenmeniz gerekir; kısa seçenekler yeterliyse getopts daha az kodla daha tutarlı bir davranış sağlar.
Değerleri doğrulamak: yutulan seçenekler ve tekrarlar
getopts bir seçeneğin değer beklediğini bildiğinde, sıradaki argümanı içeriğine bakmadan değer olarak alır. Değer tire ile başlasa bile durum değişmez. Kullanıcı -o seçeneğinin değerini yazmayı unutup hemen ardından -v yazarsa, -v ayrı bir seçenek olarak işlenmez, çıktı dosyasının adı olur. Aynı seçenek birden fazla verildiğinde ise her geçişte yeniden döndürülür ve değişkende son değer kalır. İki durumu da iz.sh ile görebilirsiniz.
bash iz.sh -o -v
# çıktı: s=o OPTARG=-v OPTIND=3
# çıktı: döngü sonu: s=? OPTIND=3
bash yedekle.sh -o a.tar -o b.tar notlar
# çıktı: ayrıntılı: 0, çıktı: b.tar, kaynaklar: notlarBu davranışlar hata değildir ama sessizce yanlış sonuç üretebilir. Önemli değerleri döngü içinde ya da döngüden hemen sonra denetleyin: bir dosya adı tire ile başlamamalıysa [[ $OPTARG == -* ]] ile kontrol edip açık bir mesajla durun. Birden fazla değer toplamak istiyorsanız tek bir değişkene atamak yerine case dalında değeri bir diziye ekleyin: hedefler+=("$OPTARG"). Dizilerle çalışmak için Bash dizi kullanımı yazısına bakabilirsiniz.
getopts değişkenleri özet tablosu
| Değişken veya öğe | Görevi | Not |
|---|---|---|
| seçenek dizesi | Tanınan harfler; harften sonra : değer alır | Başta : varsa sessiz mod |
| ad değişkeni | Bulunan seçenek harfi | Hata veya son durumunda ?, sessiz modda eksik değer için : |
| OPTARG | Seçeneğin değeri | Sessiz modda hatalı harfi taşır |
| OPTIND | Sıradaki argümanın sırası | Kendiliğinden sıfırlanmaz; shift $((OPTIND - 1)) |
| OPTERR | 1 iken mesajlar yazılır | 0 yapılırsa mesajlar kapanır |
Sık yapılan hatalar

- shift $(( OPTIND - 1 )) satırını unutmak. Seçenekler
"$@"içinde kalır ve kaynak listesi gibi işlenir. - case içinde ? yazmak. Kaçırılmamış
?her tek karakterle eşleşir;\?yazın. - Fonksiyonda OPTIND'i yerel yapmamak. İkinci çağrı seçenekleri görmez.
- Seçenekleri dosya adlarından sonra beklemek.
getoptsilk seçenek olmayan argümanda durur. - Değer alan seçeneği iki noktasız tanımlamak.
"vo"yazarsanız-o arsiv.tariçindeki değer kalan argümanlara düşer. - Zorunlu seçenekleri kontrol etmemek.
getoptseksik seçeneği değil yalnızca eksik değeri fark eder; zorunluluğu döngüden sonra siz denetlersiniz.
Sık Sorulan Sorular
getopts ile getopt aynı şey mi?
Hayır. Bu yazıda anlatılan getopts, Bash'in kendi yerleşik komutudur ve kılavuzda tanımlanır. Benzer adlı harici araçlar Bash kılavuzunun kapsamında değildir; davranışları sistemden sisteme değişebileceği için kendi belgelerine bakmanız gerekir.
getopts betik içinde mi fonksiyon içinde mi kullanılmalı?
İkisi de olur. Kılavuz getopts komutunu hem betiklerin hem fonksiyonların konumsal parametrelerini ayrıştırmak için tanımlar. Fonksiyon içinde çalışırken getopts fonksiyonun kendi argümanlarını okur, çünkü fonksiyon çalıştığı sürece konumsal parametreler fonksiyonun argümanlarıyla değiştirilir. Betiğin seçeneklerini bir main fonksiyonunda ayrıştırıyorsanız fonksiyonu main "$@" diye çağırın ve OPTIND değişkenini yerel yapın; böylece aynı kabukta tekrar çağrıldığında da doğru çalışır.
main() {
local OPTIND s ad="dünya"
while getopts "a:" s; do
case $s in
a) ad=$OPTARG ;;
*) return 2 ;;
esac
done
shift $(( OPTIND - 1 ))
echo "merhaba $ad, kalan argüman: $#"
}
main -a Ece rapor.txt notlar.txt
main
# çıktı: merhaba Ece, kalan argüman: 2
# çıktı: merhaba dünya, kalan argüman: 0İkinci çağrıda hiç seçenek verilmediği için varsayılan değer kullanıldı ve OPTIND önceki çağrıdan etkilenmedi. Fonksiyonda hata durumunda exit yerine return 2 kullanıldığına dikkat edin; böylece fonksiyonu çağıran kod ne yapacağına kendisi karar verebilir.
Seçenekleri yanlış sırayla verirsem ne olur?
Seçenekler kendi aralarında istenen sırada yazılabilir; -v -o x ile -o x -v aynı sonucu verir. Sınırlama seçeneklerle seçenek olmayan argümanlar arasındadır: getopts seçenek olmayan ilk argümanda durduğu için seçenekler her zaman başta gelmelidir. Kullanım mesajınızda bu sırayı göstermek kullanıcıların hata yapmasını azaltır.
Seçenek değerinde boşluk olabilir mi?
Olabilir; boşluklu değeri tek bir argüman olarak geçirmek çağıranın işidir. Kullanıcı değeri tırnak içinde yazdığında kabuk onu tek argüman yapar ve getopts bu argümanın tamamını OPTARG değişkenine koyar. Sizin göreviniz değeri kullanırken de tırnaklamaktır: cikti="$OPTARG" ataması güvenlidir, ama değeri bir komuta geçirirken "$cikti" yazmazsanız kelime bölünmesi yeniden devreye girer.
bash yedekle.sh -o "yıllık rapor.tar" notlar
# çıktı: ayrıntılı: 0, çıktı: yıllık rapor.tar, kaynaklar: notlarHata mesajlarının dilini değiştirebilir miyim?
Normal moddaki mesajlar Bash tarafından üretilir. Kendi metninizi kullanmak için seçenek dizesini iki noktayla başlatıp sessiz moda geçin ve \? ile : dallarında mesajı kendiniz yazın; yukarıdaki şablon bunu gösteriyor.
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 · Bash argümanları · Bash case · Bash while döngüsü · Bash exit kodları · Bash local değişken