Bash ile İnteraktif Menü Tasarımı: select, dialog ve whiptail Kullanımı
Kullanıcılardan girdi almanın en ilkel yolu read komutuyla bir şeyler sormak. Ama yazdığın script büyüdükçe, seçenekler çoğaldıkça bu yaklaşım hem çirkin görünmeye hem de yönetilmesi güç bir hale gelmeye başlıyor. İşte tam bu noktada interaktif menüler devreye giriyor. Bash’in yerleşik select yapısından başlayıp dialog ve whiptail gibi araçlarla profesyonel görünümlü TUI (Text User Interface) arayüzleri oluşturabilirsin. Bu yazıda sıfırdan başlayıp gerçek dünya senaryolarına kadar her şeyi ele alacağız.
Neden İnteraktif Menü?
Script yazarken hedef kitleni düşünmek zorundasın. Eğer script’i sadece kendin kullanacaksan her şeyi hardcode edebilir ya da argüman alacak şekilde düzenleyebilirsin. Ama sistemi tanımayan bir operatöre, müşteriye ya da yeni bir ekip üyesine kullandıracaksan işler değişiyor.
İnteraktif menüler şu durumlarda hayat kurtarır:
- Sunucu kurulum ve konfigürasyon scriptleri
- Yedekleme ve geri yükleme araçları
- Servis yönetim panelleri
- Kullanıcı yönetim scriptleri
- Deploy ve rollback araçları
Şimdi araçlarımıza bakalım.
Bash’in Yerleşik select Yapısı
select, harici bir araç gerektirmeden temel menüler oluşturmana izin veren Bash built-in’idir. Sözdizimi for döngüsüne benzer ve kullanımı son derece kolaydır.
Temel select Kullanımı
#!/bin/bash
echo "Hangi servisi yönetmek istiyorsunuz?"
select servis in "Nginx" "Apache" "MySQL" "PostgreSQL" "Çıkış"; do
case $servis in
"Nginx")
echo "Nginx seçildi."
systemctl status nginx
;;
"Apache")
echo "Apache seçildi."
systemctl status apache2
;;
"MySQL")
echo "MySQL seçildi."
systemctl status mysql
;;
"PostgreSQL")
echo "PostgreSQL seçildi."
systemctl status postgresql
;;
"Çıkış")
echo "Çıkılıyor..."
break
;;
*)
echo "Geçersiz seçenek. Lütfen listeden bir numara girin."
;;
esac
done
select çalıştığında seçenekleri otomatik olarak numaralandırır ve PS3 değişkeninde tanımlı olan prompt’u gösterir. Varsayılan prompt #? şeklindedir, bunu özelleştirmek için:
#!/bin/bash
PS3="Seçiminizi yapın (1-4): "
ortamlar=("Development" "Staging" "Production" "İptal")
select ortam in "${ortamlar[@]}"; do
case $ortam in
"Development"|"Staging"|"Production")
echo "Seçilen ortam: $ortam"
echo "Deploy işlemi başlatılıyor..."
# deploy_script.sh $ortam
break
;;
"İptal")
echo "İşlem iptal edildi."
break
;;
*)
echo "Hatalı seçim: $REPLY"
;;
esac
done
Burada $REPLY değişkeni kullanıcının girdiği ham değeri tutar, $ortam ise seçilen string’i tutar. İkisi arasındaki farkı anlamak önemli.
select ile İç İçe Menüler
Gerçek dünyada tek seviyeli menüler yeterli olmaz. İşte iç içe menü örneği:
#!/bin/bash
PS3="Ana menü seçimi: "
ana_menu() {
echo ""
echo "=== Sunucu Yönetim Paneli ==="
select secim in "Servis Yönetimi" "Disk İşlemleri" "Kullanıcı Yönetimi" "Çıkış"; do
case $secim in
"Servis Yönetimi")
servis_menu
break
;;
"Disk İşlemleri")
disk_menu
break
;;
"Kullanıcı Yönetimi")
kullanici_menu
break
;;
"Çıkış")
echo "Güle güle!"
exit 0
;;
*)
echo "Geçersiz seçim."
;;
esac
done
ana_menu
}
servis_menu() {
PS3="Servis işlemi: "
echo ""
echo "--- Servis Yönetimi ---"
select islem in "Başlat" "Durdur" "Yeniden Başlat" "Durum Göster" "Ana Menüye Dön"; do
case $islem in
"Başlat"|"Durdur"|"Yeniden Başlat"|"Durum Göster")
echo "$islem işlemi seçildi."
break
;;
"Ana Menüye Dön")
PS3="Ana menü seçimi: "
break
;;
*)
echo "Geçersiz seçim."
;;
esac
done
}
disk_menu() {
PS3="Disk işlemi: "
echo ""
echo "--- Disk İşlemleri ---"
select islem in "Disk Kullanımı" "Bölüm Listesi" "Ana Menüye Dön"; do
case $islem in
"Disk Kullanımı")
df -h
break
;;
"Bölüm Listesi")
lsblk
break
;;
"Ana Menüye Dön")
PS3="Ana menü seçimi: "
break
;;
esac
done
}
kullanici_menu() {
echo "Kullanıcı yönetimi henüz implemente edilmedi."
}
ana_menu
select oldukça sade ve her sistemde çalışır. Ama görsel olarak zayıf. Daha profesyonel bir görünüm istiyorsan dialog veya whiptail şart.
dialog ile Profesyonel TUI Arayüzleri
dialog, ncurses tabanlı bir araç olup terminal içinde pencereler, form alanları, dosya seçiciler ve daha fazlasını oluşturmana izin veriyor. Debian/Ubuntu’da apt install dialog, RHEL/CentOS’ta yum install dialog ile kurabilirsin.
dialog Temel Widget’ları
dialog‘un en çok kullandığım widget’ları şunlar:
- –msgbox: Bilgi mesajı gösterir
- –yesno: Evet/Hayır onay kutusu
- –inputbox: Metin girişi
- –passwordbox: Şifre girişi (karakterler gizlenir)
- –menu: Seçim menüsü
- –checklist: Çoklu seçim listesi
- –radiolist: Tekli seçim listesi
- –gauge: İlerleme çubuğu
- –textbox: Metin dosyası görüntüleyici
- –fselect: Dosya seçici
Gerçek Dünya: Sunucu Kurulum Scripti
Aşağıdaki örnek, dialog kullanarak interaktif bir web sunucusu kurulum scripti oluşturuyor:
#!/bin/bash
# Geçici dosya çıktılar için
GECICI=$(mktemp)
# Çıkışta geçici dosyayı temizle
trap "rm -f $GECICI" EXIT
# Ekranı temizle
clear
# Hoşgeldin mesajı
dialog --title "Web Sunucu Kurulum Aracı"
--msgbox "Bu araç web sunucunuzu otomatik olarak yapılandıracaktır.nnDevam etmek için OK butonuna basın."
10 50
# Web sunucu seçimi
dialog --title "Web Sunucu Seçimi"
--menu "Kurmak istediğiniz web sunucuyu seçin:"
15 50 4
"1" "Nginx (Önerilen)"
"2" "Apache2"
"3" "Lighttpd"
"4" "Çıkış"
2> $GECICI
SUNUCU_SECIM=$?
# ESC veya Cancel kontrolü
if [ $SUNUCU_SECIM -ne 0 ]; then
dialog --msgbox "Kurulum iptal edildi." 7 30
exit 1
fi
SUNUCU=$(cat $GECICI)
# Seçime göre paket adı belirle
case $SUNUCU in
1) PAKET="nginx" ;;
2) PAKET="apache2" ;;
3) PAKET="lighttpd" ;;
4) exit 0 ;;
esac
# Ek bileşen seçimi (checklist)
dialog --title "Ek Bileşenler"
--checklist "Kurmak istediğiniz ek bileşenleri seçin (SPACE ile seçin):"
15 60 5
"php" "PHP Desteği" OFF
"ssl" "SSL/TLS Sertifika Kurulumu" ON
"firewall" "UFW Firewall Yapılandırması" ON
"logrotate" "Log Rotation Ayarları" OFF
"monitoring" "Temel İzleme Araçları" OFF
2> $GECICI
BILESENLER=$(cat $GECICI)
# Onay ekranı
dialog --title "Kurulum Özeti"
--yesno "Aşağıdaki bileşenler kurulacak:nnWeb Sunucu: $PAKETnEk Bileşenler: $BILESENLERnnDevam etmek istiyor musunuz?"
12 60
if [ $? -ne 0 ]; then
dialog --msgbox "Kurulum iptal edildi." 7 30
exit 1
fi
# Kurulum simülasyonu (gauge ile ilerleme gösterimi)
{
echo 10; sleep 1
echo 30; sleep 1
echo 50; sleep 1
echo 70; sleep 1
echo 90; sleep 1
echo 100; sleep 1
} | dialog --title "Kurulum İlerliyor"
--gauge "Paketler yükleniyor, lütfen bekleyin..."
8 50 0
dialog --title "Kurulum Tamamlandı"
--msgbox "$PAKET başarıyla kuruldu!nnServisi başlatmak için:nsystemctl start $PAKET"
10 50
Bu scriptte dikkat etmen gereken birkaç önemli nokta var. dialog çıktısını stderr’a yazar, bu yüzden 2> $GECICI kullanıyoruz. Ayrıca $? dönüş değeri OK için 0, Cancel için 1, ESC için 255 döner.
whiptail: dialog’un Hafif Kardeşi
whiptail, newt kütüphanesini kullanan ve dialog‘a kıyasla çok daha hafif bir alternatif. Raspberry Pi gibi kısıtlı sistemlerde, Docker container’larında ya da Debian tabanlı sistemlerde sıklıkla tercih ediliyor. Raspberry Pi’nin raspi-config aracı da whiptail ile yazılmış.
whiptail‘in dialog‘dan en önemli farkı --gauge widget’ını desteklememesi. Bunun dışında sözdizimi neredeyse birebir aynı.
whiptail ile Kullanıcı Yönetim Scripti
#!/bin/bash
GECICI=$(mktemp)
trap "rm -f $GECICI" EXIT
# whiptail'in mevcut olup olmadığını kontrol et
if ! command -v whiptail &> /dev/null; then
echo "whiptail bulunamadı. Kuruluyor..."
apt-get install -y whiptail 2>/dev/null ||
yum install -y newt 2>/dev/null ||
{ echo "whiptail kurulamadı."; exit 1; }
fi
BOYUT=$(stty size)
SATIRLAR=$(echo $BOYUT | cut -d' ' -f1)
SUTUNLAR=$(echo $BOYUT | cut -d' ' -f2)
kullanici_ekle() {
# Kullanıcı adı girişi
whiptail --title "Kullanıcı Ekle"
--inputbox "Eklemek istediğiniz kullanıcı adını girin:"
10 50 ""
2> $GECICI
[ $? -ne 0 ] && return
KULLANICI=$(cat $GECICI)
if [ -z "$KULLANICI" ]; then
whiptail --msgbox "Kullanıcı adı boş olamaz!" 8 40
return
fi
if id "$KULLANICI" &>/dev/null; then
whiptail --msgbox "Bu kullanıcı zaten mevcut: $KULLANICI" 8 50
return
fi
# Şifre girişi
whiptail --title "Şifre Belirleme"
--passwordbox "Kullanıcı şifresini girin:"
10 50
2> $GECICI
[ $? -ne 0 ] && return
SIFRE=$(cat $GECICI)
# Grup seçimi
whiptail --title "Grup Seçimi"
--checklist "Kullanıcıyı eklemek istediğiniz grupları seçin:"
15 50 5
"sudo" "Yönetici Yetkileri" OFF
"docker" "Docker Grubu" OFF
"www-data" "Web Sunucu Grubu" OFF
"git" "Git Grubu" OFF
"backup" "Yedekleme Grubu" OFF
2> $GECICI
GRUPLAR=$(cat $GECICI | tr -d '"')
# Onay
whiptail --title "Onay"
--yesno "Kullanıcı oluşturulacak:nnKullanıcı: $KULLANICInGruplar: $GRUPLARnnOnaylıyor musunuz?"
12 50
if [ $? -eq 0 ]; then
useradd -m -s /bin/bash "$KULLANICI"
echo "$KULLANICI:$SIFRE" | chpasswd
for grup in $GRUPLAR; do
usermod -aG "$grup" "$KULLANICI" 2>/dev/null
done
whiptail --msgbox "Kullanıcı '$KULLANICI' başarıyla oluşturuldu." 8 50
fi
}
kullanici_sil() {
KULLANICILAR=$(awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $5}' /etc/passwd)
if [ -z "$KULLANICILAR" ]; then
whiptail --msgbox "Silinecek kullanıcı bulunamadı." 8 40
return
fi
MENU_ITEMS=""
while IFS= read -r satir; do
AD=$(echo $satir | cut -d' ' -f1)
ACIKLAMA=$(echo $satir | cut -d' ' -f2-)
MENU_ITEMS="$MENU_ITEMS $AD "$ACIKLAMA""
done <<< "$KULLANICILAR"
eval "whiptail --title 'Kullanıcı Sil'
--menu 'Silmek istediğiniz kullanıcıyı seçin:'
15 50 8
$MENU_ITEMS"
2> $GECICI
[ $? -ne 0 ] && return
SILINECEK=$(cat $GECICI)
whiptail --title "Emin misiniz?"
--yesno "'$SILINECEK' kullanıcısı silinecek. Bu işlem geri alınamaz!nnDevam etmek istiyor musunuz?"
10 50
if [ $? -eq 0 ]; then
userdel -r "$SILINECEK" 2>/dev/null
whiptail --msgbox "Kullanıcı '$SILINECEK' silindi." 8 40
fi
}
# Ana döngü
while true; do
whiptail --title "Kullanıcı Yönetim Paneli"
--menu "İşlem seçin:"
15 50 5
"1" "Kullanıcı Ekle"
"2" "Kullanıcı Sil"
"3" "Kullanıcıları Listele"
"4" "Çıkış"
2> $GECICI
[ $? -ne 0 ] && break
case $(cat $GECICI) in
1) kullanici_ekle ;;
2) kullanici_sil ;;
3) whiptail --textbox /etc/passwd 20 70 ;;
4) break ;;
esac
done
clear
echo "Kullanıcı yönetim panelinden çıkıldı."
dialog ve whiptail Arasında Seçim Yapmak
Script’ini farklı sistemlerde çalıştıracaksan hangisinin mevcut olduğunu otomatik tespit eden bir wrapper kullanmak işini kolaylaştırır:
#!/bin/bash
# dialog veya whiptail'i otomatik seç
if command -v dialog &>/dev/null; then
DIALOG="dialog"
elif command -v whiptail &>/dev/null; then
DIALOG="whiptail"
else
echo "Hata: dialog veya whiptail bulunamadı!"
echo "Kurmak için: apt install dialog"
exit 1
fi
GECICI=$(mktemp)
trap "rm -f $GECICI" EXIT
# Artık $DIALOG değişkenini kullan
$DIALOG --title "Test"
--msgbox "Sistem: $DIALOG kullanılıyor."
8 40
Bu yaklaşım özellikle farklı Linux dağıtımlarında çalışan scriptlerde çok işe yarıyor. Ubuntu’da whiptail yüklü gelirken CentOS’ta dialog tercih edilebilir.
Renk ve Tema Özelleştirme
dialog araç renklerini özelleştirmene izin veriyor. .dialogrc dosyası oluşturarak ya da DIALOGRC environment variable’ı ile tema tanımlayabilirsin:
#!/bin/bash
# Geçici tema dosyası oluştur
TEMA=$(mktemp)
trap "rm -f $TEMA" EXIT
cat > $TEMA << 'EOF'
use_shadow = OFF
use_colors = ON
screen_color = (CYAN,BLUE,ON)
dialog_color = (BLACK,WHITE,OFF)
title_color = (BLUE,WHITE,ON)
border_color = (WHITE,WHITE,ON)
button_active_color = (WHITE,BLUE,ON)
button_inactive_color = (BLACK,WHITE,OFF)
tag_key_color = (RED,WHITE,ON)
item_selected_color = (WHITE,BLUE,ON)
EOF
export DIALOGRC=$TEMA
dialog --title "Özelleştirilmiş Tema"
--msgbox "Bu mesaj kutusu özel tema renkleriyle gösteriliyor!nnTema dosyası: $TEMA"
10 55
# Ana menü
dialog --title "Tema Demo"
--menu "Özelleştirilmiş renk teması:"
12 45 4
"1" "Birinci Seçenek"
"2" "İkinci Seçenek"
"3" "Üçüncü Seçenek"
"4" "Çıkış"
2>/dev/null
İpuçları ve Dikkat Edilmesi Gerekenler
Yıllar içinde edindiğim bazı pratik notlar:
- Geçici dosya yönetimi: Her zaman
mktempkullan,tmp_file=/tmp/dialog_outputgibi sabit isimler race condition’a yol açar. - trap kullanımı: Script sonlandığında geçici dosyaları temizlemek için mutlaka
trap "rm -f $GECICI" EXITekle. - Terminal boyutu:
stty sizeile terminal boyutunu alıp dinamik pencere boyutlandırması yapabilirsin. Küçük terminallerde sabit boyutlu pencereler kesilir. - Root kontrolü: Sistem yönetimi scriptlerinde önce root kontrolü yap, ardından menüyü başlat.
- Dönüş değerlerini kontrol et:
dialogvewhiptailCancel için 1, ESC için 255 döner. Her widget’tan sonra$?kontrol etmeyi alışkanlık haline getir. - stderr yönlendirmesi:
dialogçıktısını stderr’a yazar.2> $GECICIkullanmayı unutursan çıktıyı okuyamazsın. - SSH üzerinden kullanım: SSH bağlantılarında
TERMdeğişkeni bazen sorun çıkarır. Gerekirseexport TERM=xtermekle.
Sonuç
select, dialog ve whiptail üçlüsü Bash scriptlerini gerçek anlamda kullanıcı dostu araçlara dönüştürüyor. Sade ve hızlı bir çözüm istiyorsan select yeterli. Görsel olarak daha etkileyici, form tabanlı veya çok adımlı bir arayüz istiyorsan dialog ilk tercihin olmalı. Hafiflik ve taşınabilirlik öncelikliyse whiptail‘e yönel.
En önemli tavsiyem şu: Script’ini yazarken araç seçimini en sona bırakma. Önce hangi akışın olması gerektiğini, hangi verilerin alınacağını ve hata durumlarının nasıl yönetileceğini planla. Sonra bu planı uygun araçla hayata geçir. İnteraktif menüler sadece estetik değil, script’in hatalı kullanılmasını önleyen bir güvenlik katmanı da oluşturuyor. Doğru seçenek sunmak, kullanıcının yanlış bir şey girmesinden çok daha güvenli.
