Shell Script #7 – İnteraktif Script’ler

Bu zamana kadar yazdığımız script’lerin neredeyse tamamında bir çıktı (output) ürettik. Ancak hiçbirinde bir girdi (input) almadık.

Kullanıcıyla etkileşime geçen script’lere “etkileşimli (interactive, interaktif)” script’ler diyoruz. Etkileşim; input alma, output verme ya da ikisiyle birden de gerçekleştirebilir. Dolayısıyla bu yazıda, bir yandan çıktılarımızı biçimlendirmeyi denerken bir yanda da girdileri yönetebilmeyi deneyeceğiz.

Kod örneklerini GitHub reposunda bulabilirsiniz.

printf Kullanımı

Bu zamana kadar çıktı verirken hep “echo“dan faydalandık. Ancak echo’ya kıyasla daha esnek bir fonksiyon olan printf‘e hiç değinmemiştik.

[root@localhost ShellScripting101]# help printf
printf: printf [-v var] format [arguments]
    Formats and prints ARGUMENTS under control of the FORMAT.

    Options:
      -v var    assign the output to shell variable VAR rather than
                display it on the standard output

    FORMAT is a character string which contains three types of objects: plain
    characters, which are simply copied to standard output; character escape
    sequences, which are converted and copied to the standard output; and
    format specifications, each of which causes printing of the next successive
    argument.

    In addition to the standard format specifications described in printf(1)
    and printf(3), printf interprets:

      %b        expand backslash escape sequences in the corresponding argument
      %q        quote the argument in a way that can be reused as shell input
      %(fmt)T output the date-time string resulting from using FMT as a format
            string for strftime(3)

    Exit Status:
    Returns success unless an invalid option is given or a write or assignment
    error occurs.

Yukarıdaki yardım metninden de görülebileceği üzere, printf’i farklı kılan nokta “formatlanabilir (biçimlendirilebilir)” olmasıdır. Hemen birkaç örnekle bu özelliği anlamaya çalışalım:

[root@localhost ShellScripting101]# cat 10-printf_ornekleri.sh
#! /bin/bash

#printf örnekleri


printf Beni printf yazdı.
printf "Beni printf yazdı."
printf 'Beni printf yazdı.'


[root@localhost ShellScripting101]# ./10-printf_ornekleri.sh
BeniBeni printf yazdı.Beni printf yazdı.[root@localhost ShellScripting101]#

Çıktıya baktığınız zaman, echo’dan alışık olduğumuz bazı noktaları göremediğimizi fark edeceksiniz.

En başta yazan “Beni” kelimesi, tırnak işaretleri olmadan printf’in çok da sağlıklı çalışmadığını gösteriyor. İlk boşluğu görünce hayattan vaz geçmiş gibi bir hâli var. Yoksa cümle içinde printf gördüğü için mi patladı? Deneyin madem 🙂 Çift tırnak işaretlerinde ve tek tırnak işaretlerinde ise bir sorun görünmüyor.

Bir başta nokta ise, yine echo’dan alışık olduğumuz alt satıra geçme mantığının printf’te olmadığı. Format karakterlerinden henüz bahsetmedik, hızlı geçiyorum. Alt satıra geçmek için “\n” ifadesi bize yardımcı olacak.

[root@localhost ShellScripting101]# cat 10-printf_ornekleri.sh
#! /bin/bash

#printf örnekleri

#printf Beni printf yazdı.
#Yukarıdaki kullanım hatalıdır.

#printf varsayılan davranış olarak alt satıra GEÇMEZ:
printf "Beni printf yazdı."
printf 'Beni printf yazdı.'
#Yukarıdaki ifadeler yan yana yazılacaktır.

#Yeni satır için "\n" ifadesini kullanabiliriz:

#Önce bir satır aşağıya inelim ki üstteki örneklerle aynı satırda kalmayalım:
printf "\n"
printf "Merhaba\ndünya!\n"
#Merhaba yaz, alt satıra geç. -> Merhaba\n
#dünya! yaz, alt satıra geç. Çünkü shell prompt'umun yeni satıra düşmesini istiyorum. -> dünya!\n

[root@localhost ShellScripting101]# ./10-printf_ornekleri.sh
Beni printf yazdı.Beni printf yazdı.
Merhaba
dünya!

printf İçin Format Karakterleri (Kaçış Dizileri)

Çıktılarımızı biçimlendirmek için bize yardımcı olacak bazı kaçış dizileri var. Bu diziler, kaçış dizilerinde klasikleşmiş olan “\” karakteriyle başlıyor. Bunlardan bir tanesini, yukarıda görmüştük.

Devamını da aşağıda inceleyelim. Bu örnekte tamamı mevcut değil:

[root@localhost ShellScripting101]# cat 10-printf_ornekleri.sh
#! /bin/bash

#printf örnekleri

#printf Beni printf yazdı.
#Yukarıdaki kullanım hatalıdır.

#printf varsayılan davranış olarak alt satıra GEÇMEZ:
printf "Beni printf yazdı."
printf 'Beni printf yazdı.'
#Yukarıdaki ifadeler yan yana yazılacaktır.

#Yeni satır için "\n" ifadesini kullanabiliriz:

#Önce bir satır aşağıya inelim ki üstteki örneklerle aynı satırda kalmayalım:
printf "\n"
printf "Merhaba\ndünya!\n"
#Merhaba yaz, alt satıra geç. -> Merhaba\n
#dünya! yaz, alt satıra geç. Çünkü shell prompt'umun yeni satıra düşmesini istiyorum. -> dünya!\n


#tab (sekme) karakteri için "\t":
printf "Aramızda \t tab var.\n"

#Backspace, bildiğimiz bir karakter silme tuşu. Kendinden bir önceki karakteri siler. "\b"
printf "Ak\bli\n"
#Akbilin falan değil ne ilgisi var :)
#Akli yazıp \n ile yeni satıra geçmek istiyor.
#Ancak "k" harfinden sonra bir backspace var. Yani bu karakter silinecek.


#Çift tırnak escape'i:
printf 'Bu "konu" çok önemli.\n'
#ya da
printf "Bu \"konu\" çok önemli.\n"

#Backslash (\) escape'i:
printf 'Yeni satıra geçmek için \\n kullanılır.\n'

Çıktılar ise şu şekilde olacaktır:

[root@localhost ShellScripting101]# ./10-printf_ornekleri.sh
Beni printf yazdı.Beni printf yazdı.
Merhaba
dünya!
Aramızda         tab var.
Ali
Bu "konu" çok önemli.
Bu "konu" çok önemli.
Yeni satıra geçmek için \n kullanılır.

printf Format Örnekleri

Format karakterlerini gördük. Bu karakterler, formatlama sırasında bize yardımcı olacak. Peki tüm yapabileceklerimiz bunlar mı? Tabii ki hayır.

Aşağıdaki örnekleri inceleyiniz:

#! /bin/bash

#printf format örnekleri

#string ifadenin geleceği alana %s ekleriz:
printf "Sistemde oturum açmış kullanıcı: %s\n" "$LOGNAME"

#Birden fazla ifade varsa, değişkenleri ya da değerleri sırasıyla veririz:

printf "Sisteme bağlı kullanıcı: %s\n%s kullanıcısının SSH istemcisi: %s\nSistem dili: %s\nBunu da öylesine yazmak istedim: %s\n" "$LOGNAME" "$LOGNAME" "$SSH_CLIENT" "$LANG" "sabit değer"

Çıktı ise şu şekildedir:

Sistemde oturum açmış kullanıcı: root
Sisteme bağlı kullanıcı: root
root kullanıcısının SSH istemcisi: 10.2.2.2 55088 22
Sistem dili: tr_TR.UTF-8
Bunu da öylesine yazmak istedim: sabit değer

Değişkenlerinizin yerleşmesini istediğiniz karakter miktarını belirtme şansınız da mevcut:

#! /bin/bash

#Yazılacak değerlerin kaç karakterlik yer tutmasını istediğinizi de belirtebilirsiniz:
#Karakter sayısı belirtilmeden:
printf "\n\n\n"
printf "%s\t%s\n" "Value" "MD5"
printf "%s\t%s\n" "1" "86318e52f5ed4801abe1d13d509443de"
printf "%s\t%s\n" "2" "a53487374865fb304e96c84045ea32a2"
printf "%s\t%s\n" "3" "Hash yok"
printf "%s\t%s\n" "4" "7a9b46ab6d983a85dd4d9a1aa64a3945"

#Bu kısımda, ikinci kolondaki değerlerin 32 karakterlik yer tutmasını istediğimizi belirtiyoruz.
printf "**********\n"
printf "%s\t%32s\n" "Value" "MD5"
printf "%s\t%32s\n" "1" "86318e52f5ed4801abe1d13d509443de"
printf "%s\t%32s\n" "2" "a53487374865fb304e96c84045ea32a2"
printf "%s\t%32s\n" "3" "Hash yok"
printf "%s\t%32s\n" "4" "7a9b46ab6d983a85dd4d9a1aa64a3945"

Çıktı ise şu şekilde olacaktır:




Value   MD5
1       86318e52f5ed4801abe1d13d509443de
2       a53487374865fb304e96c84045ea32a2
3       Hash yok
4       7a9b46ab6d983a85dd4d9a1aa64a3945
**********
Value                                MD5
1       86318e52f5ed4801abe1d13d509443de
2       a53487374865fb304e96c84045ea32a2
3                               Hash yok
4       7a9b46ab6d983a85dd4d9a1aa64a3945
printf ile formatlama örneği
printf ile formatlama örneği

read Kullanımı

read” ifadesi, kullanıcıdan ya da bir dosyadan input almak amacıyla kullanılır. read ifadesi işlenirken, aşağıdaki mantık takip edilir:

  • Input, token’lar hâlinde alınır. Token dediğimiz şey ise, birbiri ardına sıralanmış karakterlerdir. Tokenlar birbirinden “whitespace” karakterleriyle ayrılır. Tabii ki token, çift tırnak işaretleri arasına alınarak boşluk içermesi sağlanabilir.
  • Yukarıdaki konuyu biraz daha açıklamaya çalışalım. Input’ları birbirinden ayırmak için kullanılan karakterlere “IFS (Input Field Seperator)” diyoruz. Varsayılan olarak boşluk, tab ve yeni satır karakterleri kullanılır. Ancak dilerseniz, bu davranışı değiştirebilirsiniz: Virgül, noktalı virgül gibi.
  • İlk token, ilk değişkene atanır.
  • Token sayısı, değişken sayısından fazlaysa; son değişken tüm token’ları tutar.
  • Eğer değişken sayısı, token sayısından fazlaysa; fazlalık değişkenlerin değeri “null” olur.
  • Eğer bir değişken belirtilmediyse, token’lar “$REPLY” değişkeninde tutulur.

Bunların hepsini açıklamaya ve anlamaya çalışacağız.

Aşağıdaki örnekte read, 3 değişken için değer bekliyor: sayi1, sayi2 ve sayi3. Sonrasında aralarında birer boşluk bırakarak 3 sayı yazıyorum ve enter’a basıyorum. Verdiğim input’lar, değişkenlere sırasıyla atanıyor:

[root@localhost ShellScripting101]# read sayi1 sayi2 sayi3
19 28 35
[root@localhost ShellScripting101]# echo $sayi1
19
[root@localhost ShellScripting101]# echo $sayi2
28
[root@localhost ShellScripting101]# echo $sayi3
35
[root@localhost ShellScripting101]#

Token sayısı, değişken sayısından fazla olursa ne olur?:

[root@localhost ShellScripting101]# read esya1 esya2
klavye monitör fare hoparlör
[root@localhost ShellScripting101]# echo $esya1
klavye
[root@localhost ShellScripting101]# echo $esya2
monitör fare hoparlör
[root@localhost ShellScripting101]#

Görüldüğü üzere, ilk token ilk değişkene atandı. Kalan tüm token’lar ise son değişkene atandı.

Peki değişken sayısı, token sayısından fazla olursa ne olur?:

[root@localhost ShellScripting101]# read degisken1 degisken2 degisken3
token1 token2
[root@localhost ShellScripting101]# echo $degisken1
token1
[root@localhost ShellScripting101]# echo $degisken2
token2
[root@localhost ShellScripting101]# echo $degisken3

[root@localhost ShellScripting101]#

Görüldüğü üzere; birinci token birinci değişkene, ikinci token ikinci değişkene atandı. Üçüncü değişken ise null kaldı.

Eğer bir değişken ismi belirtilmezse, token’lar $REPLY değişkeninde tutulur:

[root@localhost ShellScripting101]# read
Bu token'lar nerede saklanacak?
[root@localhost ShellScripting101]# echo $REPLY
Bu token'lar nerede saklanacak?
[root@localhost ShellScripting101]#

Şimdi kullanıcıdan bazı değerler alıp bunları kullanmayı deneyelim:

[root@localhost ShellScripting101]# cat 11-read_ornekleri.sh
#! /bin/bash

#Read örnekleri:


#Kullanıcıya bir mesaj göster:
printf "İsmin nedir?: "
#Gelen inputu isim değişkenine ata:
read isim
#Kullanıcıya yeni bir mesaj göster:
printf "Hangi yılda doğdun?: "
#Gelen inputu dogumyili değişkenine ata:
read dogumyili

#Şu anki yılı öğren:
let yil=$(date +"%Y")
#Yaşı hesapla
let yas=yil-dogumyili
#Kullanıcıya mesajını göster:
printf "E o zaman sen %d yaşındasın %s, öyle mi?\n" "$yas" "$isim"

Yukarıdaki kodun çıktısı, aşağıdaki gibi olacaktır. Dikkat etmenizi istediğim nokta, input doğrulaması yapmadık. Kullanıcı harf yazabilir, boş bırakabilir. Bu da bizim script’imizin sağlıklı çalışmasını engelleyebilir. Bu noktaların tamamını göz ardı ettik:

[root@localhost ShellScripting101]# ./11-read_ornekleri.sh
İsmin nedir?: Ali
Hangi yılda doğdun?: 1992
E o zaman sen 29 yaşındasın Ali, öyle mi?
[root@localhost ShellScripting101]#
read ifadesi ile interaktif shell script örneği
read ifadesi ile interaktif shell script örneği