<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//TR"> <HTML> <HEAD> <META http-equiv="Content-Type" content="text/html; charset=iso-8859-9"> <META NAME="GENERATOR" CONTENT="lfparser_2.17"> <META NAME="LFCATEGORY" CONTENT="UNIX Basics"> <!-- this is used be a number of tools: =LF=AUTHOR: Katja and Guido Socher =LF=CAT___: UNIX Basics =LF=TITLE_: Kabuk Programlama =LF=NUMBER: 216 =LF=ANAME_: article216.shtml --> <TITLE>lf216, UNIX Basics: Kabuk Programlama</TITLE> <!-- stylesheet added by lfparser: --> <style type="text/css"> <!-- td.top {font-family: Arial,Geneva,Verdana,Helvetica,sans-serif; font-size:12 } pre { font-familiy:monospace,Courier } p.cl { color:#EE9500 } a.nodec { text-decoration:none } p.trans { font-size:8pt; text-align:right } p.clbox { width:50%; alignment:center; background-color:#FFD700; border-style:none; border-width:medium; border-color:#FFD700; padding:0.5cm ; text-align:center } p.foot { background-color:#AAAAAA; color:#FFFFFF; border-style:none; border-width:medium; border-color:#AAAAAA; padding:0.5cm ; margin-top:0.1cm; margin-right:1cm; margin-left:1cm; text-align:center } --> </style> </HEAD> <BODY bgcolor="#ffffff" text="#000000"> <!-- this is generated html code. NEVER use this file for your translation work. Instead get the file with the same article number and .meta.shtml in its name. Translate this meta file and then use lfparser program to generate the final article --> <!-- lfparser can be obtained from http://www.linuxfocus.org/~guido/dev/lfparser.html --> <!-- 2pdaIgnoreStart --> <!-- start navegation bar --> <!-- top navegation bar --> <TABLE cellspacing="0" cellpadding="0" border="0" align="center" width="90%"> <TR bgcolor="#2e2292"> <TD class="top"><TABLE cellspacing="0" cellpadding="0" border="0" width= "100%"> <TR><TD width="144"><IMG src="../../common/images/logolftop.gif" alt="[LinuxFocus-icon]" width="350" height="45" align="left" border="0"></TD> <TD class="top"> <TABLE width="100%"> <TR align="right"> <TD class="top"><A class="nodec" href="../index.shtml"><FONT color= "#DDDDDD">Ev</FONT></A> | <A class= "nodec" href="../map.html"><FONT color= "#DDDDDD">Erişimdüzeni</FONT></A> | <A class= "nodec" href="../indice.html"><FONT color= "#DDDDDD">İçindekiler</FONT></A> | <A class="nodec" href="../Search/index.shtml"><FONT color= "#DDDDDD">Arama</FONT></A> </TD> </TR> <TR align="right"> <TD class="top"> <HR width="100%" noshade size="1"> </TD> </TR> </TABLE> </TD> </TR> </TABLE> </TD> </TR> </TABLE> <!-- end top navegation bar --> <!-- blue bar --> <TABLE cellspacing="0" cellpadding="0" border="0" align="center" width="90%"> <TR bgcolor="#00ffff"> <TD><IMG src="../../common/images/transpix.gif" width="1" height= "2" alt=""></TD> </TR> </TABLE> <!-- end blue bar --> <!-- bottom navegation bar --> <TABLE cellspacing="0" cellpadding="0" border="0" align="center" width="94%"> <TR bgcolor="#000000"> <TD> <TABLE cellspacing="0" cellpadding="1" border="0" width= "100%"> <TR align="center"> <TD><A class="nodec" href="../News/index.html"><FONT color= "#FFFFFF">Duyumlar</FONT></A> </TD> <TD><FONT color="#FFFFFF">|</FONT> </TD> <TD><A class="nodec" href="../Archives/index.html"><FONT color= "#FFFFFF">Belgelikler</FONT></A> </TD> <TD><FONT color="#FFFFFF">|</FONT> </TD> <TD><A class="nodec" href="../Links/index.html"><FONT color= "#FFFFFF">Bağlantılar</FONT></A> </TD> <TD><FONT color="#FFFFFF">|</FONT> </TD> <TD><A class="nodec" href="../aboutus.html"><FONT color= "#FFFFFF">LF Nedir</FONT></A> </TD> </TR> </TABLE> </TD> </TR> </TABLE> <!-- end bottom navegation bar --> <!-- stop navegation bar --> <!-- SSI_INFO --> <!-- tr_staticssi include virtual --> <!-- tr_staticssi exec cmd --> <!-- addedByLfdynahead ver 1.1 --><TABLE ALIGN="right" border=0><TR><TD ALIGN="right"><FONT SIZE="-1" FACE="Arial,Helvetica">Bu makalenin farklı dillerde bulunduğu adresler: <A href="../../English/September2001/article216.shtml">English</a> <A href="../../Castellano/September2001/article216.shtml">Castellano</a> <A href="../../Deutsch/September2001/article216.shtml">Deutsch</a> <A href="../../Francais/September2001/article216.shtml">Francais</a> <A href="../../Nederlands/September2001/article216.shtml">Nederlands</a> <A href="../../Portugues/September2001/article216.shtml">Portugues</a> <A href="../../Turkce/September2001/article216.shtml">Turkce</a> </FONT></TD></TR></TABLE><br> <!-- 2pdaIgnoreStop --> <!-- SHORT BIO ABOUT THE AUTHOR --> <TABLE ALIGN=LEFT BORDER=0 hspace=4 vspace=4 WIDTH="30%" > <TR> <TD> <!-- 2pdaIgnoreStart --> <!-- PALM DOC --> <TABLE BORDER=0 hspace=4 vspace=4> <TR> <TD> <font size=1> <img src="../../common/images/2doc.gif" width=34 align=left border=0 height=22 alt="convert to palm"><a href="http://cgi.linuxfocus.org/cgi-bin/2ztxt">Convert to GutenPalm</a><br>or <a href="http://cgi.linuxfocus.org/cgi-bin/2pda">to PalmDoc</a></font> </TD> </TR> </TABLE> <!-- END PALM DOC --> <!-- 2pdaIgnoreStop --> <br> <IMG src="../../common/images/KatjaAndGuido.jpg" alt= "[Photo of the Authors]" height="150" width="168"> <BR>tarafından <A href= "mailto:katja@linuxfocusorg, guido@linuxfocus.org">Katja and Guido Socher</A> <BR><BR> <I>Yazar hakkında:</I><BR> <P> Katja LinuxFocus'un Alman editörüdür. Tux, film, fotografçılığı ve denizi sever. Ana sayfasına <A href="http://www.toppoint.de/~utuxfan/k/">buradan ulaşabiliriz</A>. </P><P> Guido uzun zamandan beri bir Linux hayranı ve Linux'u dürüst ve açık insanlar tarafından tasarlandığı için seviyor. İşte bu ona açık kodlu dememizin bir nedeni... Guido'nun sanaldoku sayfası: <A href="http://main.linuxfocus.org/~guido/">linuxfocus.org/~guido</A></P> <BR><i>İçerik</i>: <UL> <LI><A HREF="#216lfindex0">Neden kabuk programlama ?</A></LI> <LI><A HREF="#216lfindex1">Betiğin oluşturulması</A></LI> <LI><A HREF="#216lfindex2">Yorumlar</A></LI> <LI><A HREF="#216lfindex3">Değişkenler</A></LI> <LI><A HREF="#216lfindex4">Kabuk komutları ve denetim yapıları</A></LI> <LI><A HREF="#216lfindex5">Örnekler</A></LI> <LI><A HREF="#216lfindex6">Hata ayıklama</A></LI> <LI><A HREF="#216lfindex7">Kaynaklar</A></LI> <LI><A HREF="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=216&lang=en">Bu yazı için görüş bildiriminde bulunabilirsiniz</A></LI> </UL> </TD></TR></TABLE> <!-- HEAD OF THE ARTICLE --> <br> <H2>Kabuk Programlama</H2> <IMG src="../../common/images/illustration216.jpg" width="199" height="150" alt="[Illustration]" hspace="10"> <!-- ABSTRACT OF THE ARTICLE --> <h3>Çeviri : Ceyhun ELMAS ve Erdal MUTLU</h3> <P><i>Özet</i>: <P> Bu yazıda küçük bir kabuk betiğinin nasıl yazılacağı pek çok örnekle veriliyor. </P> <HR size="2" noshade align="right"><BR> <!-- BODY OF THE ARTICLE --> <A NAME="216lfindex0"> </A> <H2>Neden kabuk programlama ?</H2> Linux için çok çeşitli grafiksel arayüzler sağlansa bile kabuk henüz en düzgün araçtır. Kabuk yalnızca bir komutlar yığını değil aynı zamanda çok iyi bir programlama dilidir. Pek çok işlemi bununla otomatik olarak yapabilirsiniz, özellikle sistem yönetimiyle ilgili konularda çok iyidir, Eğer tasarımınız doğruysa hemen deneyebilir ve kullanışlı basit prototipler oluşturabilirsiniz. Verimliliğin yapılandırmanın, bakımın ve uyumun kolaylığından daha az önemli olduğu basit işlemli küçük uygulamalar için çok kullanışlıdır. <BR> Haydi nasıl çalıştığına bakalım: <BR> <A NAME="216lfindex1"> </A> <H2>Betiğin oluşturulması</H2> Linux için pek çok kabuk bulunmaktadır fakat genellikle kabuk programlama için, ücretsiz ve kulanımı kolay olan bash (bourne again shell) kullanılır. Dolayısıyla bu yazıdaki tüm betikleri bash kullanarak yazdık (ancak zamanın çoğunda bu yaşlı kızkardeş bourne kabuğu ile koşacak).<BR> Kabuk programlarımızı yazmak için her çeşit metin editörü kullanabiliriz, örneğin, nedit, kedit, emacs, vi... diğer programlama dillerinde olduğu gibi.<BR> Program aşağıdaki satırla başlamalıdır.(bu , dosyadaki ilk satır olmalıdır):<BR> <PRE> #!/bin/sh </PRE> The #! karakterleri sisteme, bu karakterleri takip eden argumanın bu dosyayı çalıştırmakta kullanacağını söyler. Burada kullandığımız kabuk /bin/sh 'dır.<BR> Bir betik yazdığınızda ve bunu kayıt ettiğinizde bu betiği kullanabilmek için çalıştırılabilir yapmalısınız. <BR> Betiği bu şekilde çalıştırılabilir yapın:<BR> chmod +x filename <BR> Sonra betiği <TT>./filename</TT> komutuyla çalıştırabilirsiniz. <BR> <A NAME="216lfindex2"> </A> <H2>Yorumlar</H2> Betik programlarında yorumlar # ile başlar ve satırın sonuna kadar gider. Biz gerçekten yorum kullanmanızı öneriyoruz. Eğer betik içine yorumlar koyarsanız bu betiğe gereksinim duyduğunuz zamanlarda ne yaptığını ve nasıl çalıştığını zaman kaybetmeden anlamış olacaksınız. <BR> <A NAME="216lfindex3"> </A> <H2>Değişkenler</H2> Diğer programlama dillerinde değişkenler olmadan yaşayamazsınız. Betik programlarında tüm değişkenler veritipi dizgisine sahiptir ve bunları yayınlama. Değişkene değer atamak şöyle olur: <PRE> degisken=deger </PRE> Değeri görmek için değişkenin önüne dolar işareti koymak yeterlidir: <PRE> #!/bin/sh # Bir değer ata: a="Merhaba Dünya" # Şimdi "a" nın değerini yaz: echo "a nın değeri:" echo $a </PRE> Bu satırları metin editörünüzde yazın ve "first" ismiyle kayıt edin. Sonra chmod +x komutuyla betiği çalıştırılabilir yapın ve ./first komutuyla çalıştırın. <BR> Betiğin çıktısı böyle olacaktır : <PRE> a nın değeri: Merhaba Dünya </PRE> Bazen bu durum yazının diğer kısımlarıyla değişken isimlerinin karışmasına yol açabilir. <PRE> num=2 echo "this is the $numnd" </PRE> Bu "this is the 2nd" yazmayacaktır.Çıktı : "this is the " olacaktır. Çünkü betik numnd adı verilen değişkeni arayacak ve bir değere sahip olmadığını bulacaktır. Burada parantezleri kullanırsak : <PRE> num=2 echo "this is the ${num}nd" </PRE> Bu istediğimizi yazacaktır: this is the 2nd <BR> <BR> Burada değişkenlerin sayısı herzaman otomatik olarak belirlenir Bunları ilk kullanışımızda tekrar ele alacağız. <BR> <BR> Eğer matematiksel ifadelere gereksiniminiz varsa expr gibi programlar kullanmalısınız (aşagıdaki tabloda görünüyor). <BR> Ayrıca betikte geçerli olan değişkenler aynı zamanda çevre değişkenleridir. Değişken açkısözcük tarafından önce alınır , çevre değişkenleri ihraç edilir. Bunlardan burada daha fazla sözetmeyeceğiz. Bunlar normalde yalnızca sistemgiriş betiklerinde kullanılır. <A NAME="216lfindex4"> </A> <H2>Kabuk komutları ve denetim yapıları</H2> Kabuk betiklerinde kullanılacak üç sınıf komut vardır: <BR> <BR> <B>1)Unix komutları:</B><BR> Kabuk betiklerinde her Unix komutunun kullanılabilmesine karşın, diğerlerine göre daha fazla kullanımı olan komutlar vardır. Bu komutlar genellkle dosya ve metin işlemleri ile ilgilidir. <BR> <TABLE bgcolor="#aaaaff" border="1" align="center"> <TR> <TH width="30%">Komut kullanımı (syntax)</TH> <TH>Amaç</TH> </TR> <TR> <TD>echo "metin kısmı"</TD> <TD>Metin kısmını ekrana yazar.</TD> </TR> <TR> <TD>ls</TD> <TD>Dosyaları listeler.</TD> </TR> <TR> <TD>wc -l dosya<BR> wc -w dosya<BR> wc -c dosya</TD> <TD>Dosyadaki stırları sayar veya<BR> sözcükleri veya<BR> karatkterleri sayar.</TD> </TR> <TR> <TD>cp kaynakdosya hedefdosya</TD> <TD>Kaynakdosya'yı hedefdosya olarak kopyalar.</TD> </TR> <TR> <TD>mv eskiad yeniad</TD> <TD>Dosya adını değiştirir veya dosyayı taşır.</TD> </TR> <TR> <TD>rm dosya</TD> <TD>Dosya siler.</TD> </TR> <TR> <TD>grep 'katar' dosya</TD> <TD>Dosya içerisinde katar arar.<BR> Örnek: grep 'aranacak katar' dosya.txt</TD> </TR> <TR> <TD>cut -b sütün dosya</TD> <TD>Sabit uzunluklu metin sütünlarından veri elde etme.<BR> Örnek: 5 ile 9 arasındaki karakterleri elde eder.<BR> cut -b5-9 dosya.txt<BR> Bu komutu bam başka bir komut olan "cat" ile karıştırmayın. </TD> </TR> <TR> <TD>cat dosya.txt</TD> <TD>dosya.txt'yi standart çıktı aygıtına yazar (sizin ekranınız).</TD> </TR> <TR> <TD>file dosya</TD> <TD>Dosyanın tipi hakkında bilgi vermektedir.</TD> </TR> <TR> <TD>read değişken</TD> <TD>Kullanıcıdan aldığı değeri değişken'e yazar. </TD> </TR> <TR> <TD>sort dosya.txt</TD> <TD>dosya.txt'daki satırları sıralar(dizer).</TD> </TR> <TR> <TD>uniq</TD> <TD>Tekrarlanan satırları siler. Sadece arka arkaya gelen ve tekrarlanan satırları sildiği için sort ile birlikte kullanılabilir. <BR> Örnek: sort dosya.txt | uniq<BR> </TD> </TR> <TR> <TD>expr</TD> <TD>Kabuk içerisinde matematiksel işlemler yapar.<BR> Örnek: 2 ile 3 toplamak için<BR> expr 2 "+" 3</TD> </TR> <TR> <TD>find</TD> <TD>Dosya araması yapar.<BR> Örnek: dosya ismine göre arama:<BR> find . -name dosyaismi -print<BR> Aslında bu komutun birçok kullanımı vardır ve hepsini bu yazıda anlatmak ne yazık ki olası değildir. </TD> </TR> <TR> <TD>tee</TD> Standart çıktı aygıtına (sizin ekranınız) veri yazmak. Genellikle şu şekilde kullanılır:<BR> herhangikomut | tee çıktıdosyası<BR> Komutun çıktısını ekrana ve dosyaya yazar. </TD> </TR> <TR> <TD>basename dosya</TD> <TD>Yoltanımı(dizin) kısmını atarak sadece dosyanın adını üretir. <BR> Örnek: basename /bin/tux<BR> Sadece tux elde edilir.</TD> </TR> <TR> <TD>dirname dosya</TD> <TD> Dosya adınını atarak sadece yoltanımını (dizin) üretir. <BR> Örnek: dirname /bin/tux<BR> Sadece /bin kısmı elde edilir.</TD> </TR> <TR> <TD>head dosya</TD> <TD>Dosya başından itibaren birkaç satır yazar.</TD> </TR> <TR> <TD>tail dosya</TD> <TD>Dosya sonundan itibaren birkaç satır yazar.</TD> </TR> <TR> <TD>sed</TD> <TD>sed basit olarak bul ve değiştir programıdır. Ekrandan (veya borudan) okuduğu metinleri standart çıktı aygıtına (genelde ekran) yazar. Aranan metin düzenli ifadedir (kaynaklar kısmına bakınız). linuxfocus katarını LinuxFocus ile değiştirmek için :<BR> cat metin.dosyası | sed 's/linuxfocus/LinuxFocus/' > yenimetin.dosyası<BR> kullanabilirsiniz. Bu her satırdaki linuxfocus'ları LinuxFocus ile değiştirir. Eğer, aynı satırda birden fazla linuxfocus varsa, sadece ilkini değiştirir. Bir satırdan birden fazla aynı ifadeden varsa ve siz bunu değiştirmek istiyorsanız:<BR> cat metin.dosyası | sed 's/linuxfocus/LinuxFocus/g' > yenimetin.dosyası<BR> </TD> </TR> <TR> <TD>awk</TD> <TD> Genellikle awk bir satırdaki alanları elde etmek için kullanılmaktadır. Benimsenmiş değer olarak, alan ayracı, boşluk karakteridir. Başka bir alan ayracı belirtmek için -F seçeneği kullanılabilir. <PRE> <SMALL>cat dosya.txt | awk -F, '{print $1 "," $3 }' </SMALL> </PRE> Burada ayraç olarak virgül (,) karakteri kullanıldı ve ilk ve üçüncü ($1 $3) alanlar (sütünlar) elde edildi. Eğer, dosya.txt'nin satırları şu şekilde ise: <PRE> <SMALL>Adam Bor, 34, India Kerry Miller, 22, USA </SMALL> </PRE> o zaman sonuç: <PRE> <SMALL>Adam Bor, India Kerry Miller, USA </SMALL> </PRE> olur. Awk ile bundan çok daha fazlasını yapmak olasıdır. Bu sadece en çok kullanılan şeklidir. </TD> </TR> </TABLE> <BR> <BR> <B>2) Kavramlar: Borular, yönlendirme ve ters tırnak</B><BR> Bunlar gerçekte komut, ancak aynı zamanda da çok önemli kavramlardır. <BR> <BR> <B>Borular</B> (|) bir programın çıktısını (stdout) başka bir programın girdisi olarak vermektedir (stdin).<BR> <PRE> grep "merhaba" dosya.txt | wc -l </PRE> dosya.txt dosyasındaki merhaba kelimesini içeren satırları bulmakta ve onları saymaktadır.<BR> Grep komutunun çıktısı wc komutuna girdi olarak kullanılmıştır. Belli mantık sınırları içerisinde bu şekilde istediğiniz kadar komutu, borular ile arka arkaya kullanabilirsiniz.<BR> <BR> <B>Yönlendirme</B>: bir komutun çıktısını bir dosyaya yazmaktadır veya dosyanın arkasına eklemektedir.<BR> > çıktıyı bir dosyaya yazmaktadır. Eğer, dosya varsa, dosyanın üzerine yazmaktadır.<BR> >> çıktıyı dosyanın arkasına eklemektedir (Dosya yoksa, yeni bir dosya yaratarak içerisine yazmaktadır, ancak hiçbir zaman dosya üzerine yazmamaktadır.).<BR> <BR> <B>Ters tırnak</B><BR> Bir komutun çıktısı başka bir komuta parametre olarak (Bu yukarıdaki standart girdi (stdin) aygıtı gibi değildir, program isminden sonra verilen katarlar parametreleri oluşturmaktadır.) verilebilir. Ayrıca, bir programın çıktısını bir değişkene atamak için de kullanılabilir.<BR> <PRE> find . -mtime -1 -type f -print </PRE> Komutu, 24 saat içerisinde değiştirilmiş tüm dosyaları bulmaktadır. (-mtime -2 ise, 48 saat olura). Eğer, bütün bu dosyaları bir tar dosyası (dosya.tar) haline getirmek istiyorsanız : <PRE> tar xvf dosya.tar dosya1 dosya2 ... </PRE> Tüm dosyaları tek tek yazmaktansa, iki (find ve tar) komutu ters tırnak kullanarak birleştirebiliriz. Böylece, tar komutu, find komutunun bulduğu tüm dosyaları paketleyecektir: <PRE> #!/bin/sh # Tırnaklar ters tırnaktır (`), normal tırnak değil ('): tar -zcvf ensondegisen.tar.gz `find . -mtime -1 -type f -print` </PRE> <BR> <B>3) Denetim yapıları</B><BR> <B>"if" ifadesi</B> bir ifadenin doğru olup olmadığını denetlemektedir (Çıkış durum bilgisi 0 ise, başarılı demektir). Eğer, doğru ise "then" kısmı çalıştırılmaktadır: <PRE> if ....; then .... elif ....; then .... else .... fi </PRE> Genelde, if ifadesi, içerisinde test adı verilen bir komut kullanılmaktadır. Bu komut katar karşılaştırılmasında, dosyanın var olup olmadığının denetlenmesinde, dosyanın okuma hakkı olup olmadığını denetlenmesinde ... kullanılmaktadır.<BR> "test" komutu " [ ] " köşeli parantezler olarak yazılmaktadır. Burada kullanılan boşluklar önemlidir : Parantezlerden önce ve sonra boşluk olmasına dikkat ediniz. Örnek: <PRE> [ -f "dosya" ] : "dosya" nın dosya olup olmadığını denetler. [ -x "/bin/ls" ] : /bin/ls çalıştırılabilir bir dosya olup olmadığını denetler. [ -n "$değisken" ] : $degisken'in herhangi bir değer taşıyıp taşımadığını denetlemektedir. [ "$a" = "$b" ] : "$a" nın "$b" ye eşit olup olmadığını denetlemektedir. </PRE> "man test" komutunu çalıştırarak, tüm karşılaştırma ve dosya denetleme seçeneklerini elde edeceksiniz.<BR> Bu kabuk programını kullanmak oldukça basittir: <PRE> #!/bin/sh if [ "$SHELL" = "/bin/bash" ]; then echo "Giriş kabuğunuz bash (bourne again shell) dır." else echo "Giriş kabuğunuz bash değil $SHELL dir" fi </PRE> $SHELL değişkeni kullanılan kabuğun ismini içermektedir ve biz onu "/bin/bash" ile karşılaştırıyoruz.<BR> <BR> <B>Kısayol işlemcileri (operatörleri)</B><BR> C ile tanışık olan kişiler aşağıdaki yapıyı hemen benimseyeceklerdir:<BR> <PRE> [ -f "/etc/shadow" ] && echo "Bu bilgisayar gölge şifrelemesi (shadow passwords) kullanıyor." </PRE> && ifadesi if-ifadesine kısayol gibi kullanılabilir. İfadenin sağ tarafı ancak sol tarafı doğru olduğunda çalıştırılmaktadır. Bunu VE (AND) gibi okuyabilirsiniz. Buna göre : "/etc/shadow dosyası var VE echo çalıştırılmaktadır". VEYA (||) işlemcisi de vardır. Örnek: <PRE> #!/bin/sh eiletidizini=/var/spool/mail/james [ -r "$eiletidizini" ] || { echo "$eiletidizini dizinini okuyamıyorum" ; exit 1; } echo "$eiletidizini de eiletiniz var.:" grep "^From " $eiletidizini </PRE> Bu kabuk betiği e-ileti dizinini okuyup okuyamadığna bakmaktadır. Eğer, okuyabiliyorsa, dosyadan "From" içeren satırları ekrana yazmaktadır. Eğer $eiletidizini dosyasını okuyamıyorsa, VEYA işlemcisi devreye girmektedir. Normal İngilizce'de program parçasını şu şekilde okuyoruz: "E-ileti dizini okunabilir veya çık.". Buradaki sorun, VEYA'dan sonra sadece bir komuta yer olmasıdır, ancak bizim birden fazla komuta gereksinimiz vardır: <BR> -hata mesajı görüntüle <BR> -programdan çık <BR> Bu ikisini bir arada kullanabilmek için, bunları adı olmayan bir fonksiyon olarak grupluyoruz. Fonksiyonlar hakkında genel bilgi aşağıda verilmektedir. <BR> Herşeyi VE veya VEYA'lar kullanmadan, sadece if-ifadelerinden yararlanarak da gerçekleştirebilirsiniz, VE ve VEYA'lar biraz daha kullanışlıdır. <BR> <BR> <B>case</B> ifadesi bir katarı (kabuktaki * ve ? de kullanılabilir) birden fazla seçenekten birine uygun düşürmede kullanılmaktadır. <PRE> case ... in ...) burada birşeyler yap;; esac </PRE> Bir örnek ele alalım. Bir dosyanın tipini fıle komutunu kullanarak öğrenebiliriz: <PRE> file lf.gz sonuç: lf.gz: gzip compressed data, deflated, original filename, last modified: Mon Aug 27 23:09:18 2001, os: Unix </PRE> Şimdi biz bu komutu <A href="../../common/src/article216/smartzip.txt">smartzip</A> adında, otomatik olarak sıkıştırılmış (uncompress, bzip2, gzip ve zip) dosyaları açan bir kabuk programı yazımında kullanacağız: <PRE> #!/bin/sh ftype=`file "$1"` case "$ftype" in "$1: Zip archive"*) unzip "$1" ;; "$1: gzip compressed"*) gunzip "$1" ;; "$1: bzip2 compressed"*) bunzip2 "$1" ;; *) error "File $1 dosyası smartzip ile açılamıyor.";; esac </PRE> <BR> Eğer, dikkat ettiyseniz, burada özel bir değişken kullandık $1. Bu değişken, programa komut satırından verilen ilk parametreyi içermektedir. Programı : <BR> smartzip yazilar.zip <BR> gibi çalıştırırsak, $1'in alacağı değer yazilar.zip olacaktır. <BR> <BR> <B>select</B> ifadesi bash kabuğuna özgüdür ve etkileşimli kullanımlarda oldukça yarar sağlamaktadır. Kullanıcı, kendisine verilen bir listeden birini seçebilmektedir: <PRE> select var in ... ; do break done .... şimdi $var kullanılabilir .... </PRE> İşte örnek: <PRE> #!/bin/sh echo "En favori işletim sisteminiz hangisidir?" select var in "Linux" "Gnu Hurd" "Free BSD" "Diğer"; do break done echo "Seçiminiz $var dur." </PRE> Kabuk programı şunları gerçekleştirmektedir: <PRE> En favori işletim sisteminiz hangisidir? 1) Linux 2) Gnu Hurd 3) Free BSD 4) Diğer #? 1 Seçiminiz Linux dur." </PRE> Kabukta kullanabileceğiniz <B>döngü ifadeleri</B> şunlardır: <PRE> while ...; do .... done </PRE> <B>while-döngüsü</B> denetlenen ifade doğru olduğu sürece çalışılacaktır. Döngünün herhangi bir noktasından çıkmak için "break" kullanılabilir. Döngünün herhangi bir yerinde "continue" kullanılırsa, döngünün geriye kalanı çalıştırılmamakta ve onun yerine döngünün başına dönülmektedir. <BR> <BR> <B>for-döngüsü</B> boşluklar ile ayrılmış katar listesini parametre olarak almaktadır ve bunları sırasıyla ilgili değişkene atamaktadır: <PRE> for değişken in ....; do .... done </PRE> Aşağıdaki örnekte A dan C'ye kadar olan karakterler ekrana yazmaktadır: <PRE> #!/bin/sh for degisken in A B C ; do echo "değişkenin değeri $degisken" done </PRE> Aşağıda daha kullanışlı bir örnek yer almaktdadır. Örnek, rpmgoster adını taşımakta ve parametre olarak verilen rpm paketleri hakkında bilgi elde etmekte ve ekranda göstermektedir: <PRE> #!/bin/sh # RPM paketlerinin içeriğini listeler # KULLANIM: rpmgoster rpmdosya1 rpmdosya2 ... # ÖRNEK: rpmgoster /cdrom/RedHat/RPMS/*.rpm for rpmpaketi in $*; do if [ -r "$rpmpaketi" ];then echo "=============== $rpmpaketi ==============" rpm -qi -p $rpmpaketi else echo "HATA: $rpmpaketi dosyası okunamadı." fi done </PRE> Yukarıdaki örnekte komut satırından verilen ve tüm parametreleri içeren $* değişkenini görüyorsunuz. Programı, <BR> rpmgoster openssh.rpm w3m.rpm webgrep.rpm<BR> olarak çalıştırırsak, $* değişkeni 3 parametreyi birlikte içerecektir: openssh.rpm, w3m.rpm ve webgrep.rpm. <BR> <BR> GNU bash ayrıca until-döngüsüne de sahiptir, ancak while ve for döngüleri genellikle yeterli olmaktadır. <BR> <BR> <B>Tırnak içine alma</B><BR> Programa herhangi bir parametre göndermeden önce, kabuk joker (*, ?) karakterleri ve değişkenleri kullanmaya ve yerleştirmeye çalışmaktadır. Kullanmak ve yerleştirmeden kasıt, joker (*, ? gibi) karakterlerin yerine uygun dosya adları konulması ve değişkenlerin yerine taşıdıkları değerler ile değiştirilmesidir. Bu uygulamayı değiştirmek için tırnak kullanabilirsiniz: Sözgelimi, bulunduğumuz dizinde yer alan dosyalar arasında eileti.jpg ve tux.jpg jpg dosyaları da olsun. <PRE> #!/bin/sh echo *.jpg </PRE> Bu ekrana "eileti.jpg tux.jpg" yazacaktır.<BR> Bunu önlemek için tek veya çift tırnak kullanabiliriz: <PRE> #!/bin/sh echo "*.jpg" echo '*.jpg' </PRE> Bu ise, ekrana "*.jpg" ifadesini iki kez yazmaktadır. <BR> Tek tırnaklar daha kısıtlayıcıdır. Tek tırnak kullanıldığında, değikenlerin yerine değerlerinin konulması bile engellenmektedir: <PRE> #!/bin/sh echo $SHELL echo "$SHELL" echo '$SHELL' </PRE> Sonuç aşağıdaki gibi olacaktır: <PRE> /bin/bash /bin/bash $SHELL </PRE> Son olarak, özel anlam taşıyan herhangi bir karakteri yazmak için önüne ters bölü çizgisi kullanabiliriz: <PRE> echo \*.jpg echo \$SHELL </PRE> dolayısıyla: <PRE> *.jpg $SHELL </PRE> elde edilir.<BR><BR> <B>Bilgilendirme yeri</B><BR> Bilgilendirme yeri, birden fazla satırdan oluşan metni bir komuta göndermek istediğinizde kullanılabilir. Kabuk programlarınızda yardım metni yazarken her satırın başına echo komutunu kullanmadan yazabilmek oldukça kullanışlı olmaktadır. "Bilgilendirme yeri" << ve metnin sonunda da yazılması gereken bir başlık ile başlamaktadır. <A href="../../common/src/article216/ren.txt"> ren adındaki örnek kabuk programı</A>, yardım metni için bilgilendirme yerinden faydalanmaktadır ve yaptığı iş ise, birden fazla dosya ismini değiştirmmektir: <PRE> #!/bin/sh # Eğer, 3'ten daha az paramtre verilmişse, yardım mesajı görüntülenecektir: if [ $# -lt 3 ] ; then cat <<YARDIM ren -- birden fazla dosyanın adını sıradan ifadeler kullanarak değiştirmektedir. KULLANIMI: ren 'sıradanifade' 'yerinekonulacakifade' dosyalar... ÖRNEK: tüm *.HTM dosyalarını *.html olarak değiştirmek için: ren 'HTM$' 'html' *.HTM YARDIM exit 0 fi ESKI="$1" YENI="$2" # shift komutu, komut satırından verilen parametre listesinden # bir adet parametreyi silmektedir shift shift # Şimdi $* tüm dosyaları içermektedir: for dosya in $*; do if [ -f "$dosya" ] ; then yenidosya=`echo "$dosya" | sed "s/${ESKI}/${YENI}/g"` if [ -f "$yenidosya" ]; then echo "HATA: $yenidosya zaten var" else echo "$dosya sı $yenidosya olarak değiştirilmektedir ..." mv "$dosya" "$yenidosya" fi fi done </PRE> Bu şu ana kadar incelediğimiz en karmaşık betiktir. Bunun üzerinde biraz konuşalım. İlk if-ifadesi, komut satırından verilen parametre sayısının en azından 3 adet olup olmadığını denetlemektedir. (Özel bir değişken olan $# de parametre sayısını tutmaktadır.) Eğer, parametre sayısı yeterli değil ise, yardım mesajı cat komutuna, o da ekrana göndermektedir. Yardım mesajı görüntülendikten sonra programdan çıkılmaktadır. Eğer, 3 veya daha fazla parametre verilmiş ise, ilki ESKI, ikincisi de YENI değişkenlerine atanmaktadır. Daha sonra, shift komutu iki defa kullanılarak 3. paramtreyi ilk parametre olarak elde etmek için kaydırılmaktadır. $* daki her parametre tek tek $dosya değişkenine atanmaktadır. İlk önce dosyanın var olup olmadığı denetlenmektedir ve ondan sonra yeni dosya adı eskisi üzerinde sed komutuyla yapılan değiştirme ile elde edilmektedir. Ters tırnaklar, yeni dosya isminin yenidosya değişkenine atamak için kullanılmıştır. Artık gereksinim duyduğumuz herşeye sahibiz: eski dosya adına ve yenisine. Bu ikisi mv komutuna parametre olarak verilerek, eski dosya ismi yenisi ile değiştirilmektedir. <BR> <BR> <B>Fonksiyonlar</B><BR> Daha karışık programlar yazmaya başlar başlamaz, aynı program parçalarını birden fazla yerde kullandığınızı fark ediyorsunuz. Bunun için fonksiyonlardan yararlanabiliriz. Bir fonksiyon aşağıdaki gibi gözükmektedir: <PRE> fonksiyonismi() { # Fonksiyon gövdesinde (içerisnde) $1, fonksiyona verilen ilk parametre # $2 ikinci vs. fonksiyonun gövdesi } </PRE> Fonksiyonu kullanmadan önce, programın başında fonksiyonu "tanımlamak" gerekmektedir. <BR> <BR> Konsole penceresinin başlığını değiştirmek için <A href="../../common/src/article216/xtitlebar.txt">xtitlebar</A> adlı program kullanılabilir. Eğer, aynı anda birden fazla konsole kullanıyorsanız, başlıklarından hangisinin ne olduğunu kolayca anlayabilirsiniz. Konsole'un ismi, kendisine gönderilen kaçış kodu (escape sequence) ile değiştirilmektedir. Betik yardim adinda bir fonksiyon kullanmaktadır. Görüldüğü üzere, yardim fonksiyonu bir defa tanımlanmış ve iki yerde kullanılmıştır: <PRE> #!/bin/sh # vim: set sw=4 ts=4 et: yardim() { cat <<YARDIM xtitlebar -- xterm, gnome-terminal veya kde konsole un adı değiştirir. KULLANIMI: xtitlebar [-h] "başlık" SEÇENEKLER: -h yardim metin ÖRNEK: xtitlebar "cvs" YARDIM exit 0 } # Hata durumunda veya -h parametresi verildiğinde yardim # fonksiyonunu çağırmaktayız: [ -z "$1" ] && yardim [ "$1" = "-h" ] && yardim # konsole'un başlığını değiştirmek için kaçış kodu gönder: echo -e "\033]0;$1\007" # </PRE> Yazdığınız programlarda geniş yardım bilgilerine yer vermeniz iyi bir alışkanlıktır. Bu size ve başkalarına programı kullanırken oldukça faydalı olmaktadır. <BR> <BR> <B>Komut satırı parametreleri</B><BR> $* ve $1, $2 ... $9 komut satırından verilen parametreleri (programın adından sonra gelen veriler) içerdiklerini görmüştük. Şu ana kadar az sayıda ve oldukça basit yapıda parametre kullandık (Bir iki gerekli parametre ve -h yardım için). Ancak, çok geçmeden, komut satırından verilen parametreleri işleyecek bir işlemciye gereksinim duyacaksınız. Genelde, seçime bağlı tüm parametrelerin başı eksi işaretini koymak ve bunların diğer parametrelerden (dosya adı vs.) önce gelmesi alışılagelmiş bir uygulamadır. <BR> <BR> Parametre işlemcisi oluşturmanın birçok yolu vardır. Aşağıdaki while döngüsü ve case ifadesi <A href="../../common/src/article216/cmdparser.txt"> genel bir parametre işlemci</A> için çok uygun bir çözümdür: <PRE> #!/bin/sh yardim() { cat <<YARDIM Bu genel bir parametre işlemcisidir. ÖRNEK KULLANIM: cmdparser -l merhaba -f -- -dosya1 dosya2 YARDIM exit 0 } while [ -n "$1" ]; do case $1 in -h) yardim;shift 1;; # yardım fonksiyonu çağrıldı -f) opt_f=1;shift 1;; # opt_f değişkenine değer atandı -l) opt_l=$2;shift 2;; # -l parametresi değer almaktadır, -> shift ile 2 kaydırıldıktan sonar --) shift;break;; # seçenekler bölümünün sonu -*) echo "hata: $1 seçeneği tanımlı değildir. yardım için -h";exit 1;; *) break;; esac done echo "opt_f nin değeri $opt_f" echo "opt_l nin değeri $opt_l" echo "ilk parametre $1" echo "ikinci parametre $2" </PRE> Bunu bir deneyin! Programı aşağıdaki gibi çalıştırabilirsiniz: <PRE> cmdparser -l merhaba -f -- -dosya1 dosya2 </PRE> sonuç <PRE> opt_f nin değeri 1 opt_l nin değeri merhaba ilk parametre -dosya1 ikinci parametre dosya2 </PRE> Bu nasıl çalışmaktadır? Döngü içinde tüm parametreler tek tek case ifadesindekilere uyup uymadığı karşılaştırılmaktadır. Uyuan bir parametre bulunduğunda, değeri ilgili değişkene atanmakta ve bir kaydırılmaktadır. Unix'te, seçimler (- eksi işareti ile başlayanlar) önce gelmektedir. İki eksi (--) çizgisiyle seçimlerin bittiğini belirtebilirsiniz. Buna, eksi ile başlayan bir katarı grep ile ararken gereksiminiz olacaktır: <PRE> f.txt dosyasında -xx- arama: grep -- -xx- f.txt </PRE> Bizim parametre işlemcimiz, yukarıda da görüldüğü gibi, -- ile başlayan parametreleri de işleyebilmektedir. <A NAME="216lfindex5"> </A> <H2>Örnekler</H2> <B>Genel amaçlı program iskeleti</B><BR> <BR> Bir kabuk programı yazmak için gerekli olan tüm bileşenleri inceledik. Tüm iyi programlarda yardım bulunmalıdır ve seçenekleri işlemek, tek bir seçenek olsa bile, için genel amaçlı şeçenek işlemcimizden yararlanabilirsiniz. Dolayısıyla, başka programların yazımında temel alabileceğiniz <A href="../../common/src/article216/framework.sh.txt">framework.sh</A>, bir çerçeve programınızın olması, hiç de fena fikir değildir. Yeni bir program yazacağınız zaman, bundan bir kopya çıkartmanız yeterlidir: <PRE> cp framework.sh benimprogram </PRE> ve bundan sonra "benimprogram" adlı programda gerekli değişiklikler yapılabilir. <BR> <BR> Şimdi şu iki programı inceleyelim: <BR> <BR> <B>İkili sayı tabanda verilen bir sayısı, onlu tabana çeviren program</B><BR> <BR> <A href="../../common/src/article216/b2d.txt">b2d</A> programı, ikili sayı tabanında verilen bir sayıyı (1101 gibi) karşılığı olan onlu tabana çevirmektedir. Bu program expr kullanarak basit matematiksel işlemlerin nasıl yapılabileceğiniz göstermektedir: <PRE> #!/bin/sh # vim: set sw=4 ts=4 et: yardim() { cat <<YARDIM b2h -- ikili sayı sisteminde verilen bir sayıyı, onlu sayı sisteme çevirir KULANIM: b2h [-h] ikilisayi SEÇENEKLER: -h yardım metin ÖRNEK: b2h 111010 için sonuç 58 olur YARDIM exit 0 } hata() { # hata mesajını görüntüle ve çık echo "$1" exit 1 } sonkarakter() { # $rval değişkeni içerisine, verilen katarın son karakterini yerleştirir if [ -z "$1" ]; then # boş katar rval="" return fi # wc, çıktının sonuna biraz boşluk koymaktadır, # sed'e gereksinim duymamızın nedeni budur: karaktersayisi=`echo -n "$1" | wc -c | sed 's/ //g' ` # şimdi son karakteri elde et rval=`echo -n "$1" | cut -b $karaktersayisi` } kes() { # verilen bir katarın son karakterini kesip, geriye kalanı # $rval içine yerleştirir if [ -z "$1" ]; then # boş katar rval="" return fi # wc, çıktının sonuna biraz boşluk koymaktadır, sed'e gereksinim # duymamızın nedeni budur: karaktersayisi=`echo -n "$1" | wc -c | sed 's/ //g' ` if [ "$karaktersayisi" = "1" ]; then # katarda sadece bir karakter var rval="" return fi karaktersayisieksi1=`expr $karaktersayisi "-" 1` # son hariç hepsini al: rval=`echo -n "$1" | cut -b 0-${karaktersayisieksi1}` } while [ -n "$1" ]; do case $1 in -h) yardim;shift 1;; # yardım fonksiyonu çağırıldı --) shift;break;; # seçeneklerin sonu -*) hata "hata: böyle bir seçenek yok. Yrdım için $1. -h ";; *) break;; esac done # Programın ana kısmı toplam=0 agirlik=1 # bir parametre mutlaka verilmelidir: [ -z "$1" ] && yardim ikilisayi="$1" orjikilisayi="$1" while [ -n "$ikilisayi" ]; do sonkarakter "$ikilisayi" if [ "$rval" = "1" ]; then toplam=`expr "$agirlik" "+" "$toplam"` fi # $ikilisayi'daki son karakteri çıkart kes "$ikilisayi" ikilisayi="$rval" agirlik=`expr "$agirlik" "*" 2` done echo "İkili sayı sistemindeki $orjikilisayi nın onlu sayı sistemindeki değeri $toplam dır" </PRE> Kullanılan algoritma, sağ taraftan başlayarak, her basamaktaki sayının ağırlığını (1,2,4,8,16,..) kullanarak, eğer ilgili basamaktaki sayı 1 ise, toplam değişkenine eklemektedir. Sözgelimi "10", 0 * 1 + 1 * 2 = 2 dir. <BR> Katarın her bir basmak sayısını elde etmek için sonkarakter fonksiyonunu kullanıyoruz. Bu fonksiyon, katardaki toplam karakter sayısını bulabilmek için wc -c komutundan yararlanmaktadır. Daha sonra da, son karakteri elde etmek için cut komutundan yararlanmaktadır. kes fonksiyonu da benzer bir mantıkla çalışmaktadır, ancak yaptığı iç katardaki sona karakterden kurtulup, ona kadar olanı elde etmektir. <BR> <BR> <B>Dosya çevirme programı</B><BR> Belkide siz, göndermiş olduğunuz tüm e-iletilerinizi bir dosyada saklayanlardansınızdır. Birkaç aydan sonra bu dosyanın boyutu oldukça büyümekte ve e-ileti programıyla dosyaya olan erişimi yavaşlatnmaktadır. <A href="../../common/src/article216/rotatefile.txt">rotatefile</A> programı size yardımcı olabilir. Program, eileti dizininizin adını, adı gideneileti olsun, gidenelileti.1, gidenelileti.2 vs. olarak değiştirmektedir. <PRE> #!/bin/sh # vim: set sw=4 ts=4 et: surum="0.1" yardim() { cat <<YARDIM rotatefile -- dosya adını çevirir KULLANIM: rotatefile [-h] dosyaadi SEÇENEKLER: -h yardim metin ÖRNEK: rotatefile giden Bu program giden.2 yi giden.3, giden.1 i giden.2, giden i giden.1 olarak değiştirerek boş bir giden dosyası yaratacaktır En fazla 10'a kadar değiştirmektedir. sürüm $surum YARDIM exit 0 } hata() { echo "$1" exit 1 } while [ -n "$1" ]; do case $1 in -h) yardim;shift 1;; --) break;; -*) echo "hata: böyle bir seçenek yoktur $1. Yardım için -h";exit 1;; *) break;; esac done # girilen verileri denetleme: if [ -z "$1" ] ; then error "HATA: parametre olarak dosya vermeniz gerekmektedir, yardım için -h kullanınız" fi dosyan="$1" # .1 , .2 vs. dosyalrını adını değiştir: for n in 9 8 7 6 5 4 3 2 1; do if [ -f "$dosyan.$n" ]; then p=`expr $n + 1` echo "mv $dosyan.$n $dosyan.$p" mv $dosyan.$n $dosyan.$p fi done # orijinal dosyayı: if [ -f "$dosyan" ]; then echo "mv $dosyan $dosyan.1" mv $dosyan $dosyan.1 fi echo touch $ya touch $dosyan </PRE> Bu nasıl çalışmaktadır? Kullanıcının parametre olarak dosya verdiğini denetledikten sonra, program, 9'dan 1'e doğru bir döngü içerisine girmektedir. Dolayısıyla, 9. dosya 10, 8. dosya 9 vs. olmaktadır. Döngü bittikten sonra, orijinal dosyayi 1 olarak adını değiştirdikten sonra orijinal dosya adında boş bir dosya yaratılmaktadır. <A NAME="216lfindex6"> </A> <H2>Hata ayıklama</H2> Hata ayıklamada kullanılan en basit yöntem echo komutunu kullanmaktır. Bu komutu hatanın olabileceğini düşündüğünüz yerde kullanabilirsiniz. Bu belkide hata bulmada, kabuk programları yazan kişilerin %80'ninin kullandığı yöntemdir. Kabuk programlarının avantajı derlemeye gereksinim duymamaları ve bu yüzden echo komutunu eklemek uzun sürmemektedir. <BR> <BR> Kabukta, gerçek hata ayıklama seçeneği de vardır. Eğer, "garipbetik" adlı programda hata varsa, hatayı: <PRE> sh -x garipbetik </PRE> kullanarak bulabilirsiniz.<BR> Programı bu şekilde çalıştırdığınızda, çalıştırılan tüm komutları, değişkenlerin değerleri ve joker karakterler (*,? gibi) varsa, yerlerine karşılıklarını yerleştirerek görüntülemektedir. <BR> <BR> Ayrıca, kabukta, programı çalıştırmadan, yazım hatalarını denetleyen seçeneği de vardır. Bunun için: <PRE> sh -n sizin_programiniz </PRE> Eğer, sonuçta hiç bir şey görüntülenmiyorsa, yazılım hatası yok demektir. <BR> <BR> Bundan sonra kabuk programları yazmaya başlmanız dileği ile. İyi eylenceler! <BR> <A NAME="216lfindex7"> </A> <H2>Kaynaklar</H2> <UL> <LI>Bash kabuğun man ve info sayfaları çok iyi yazılmış ve orada birçok faydalı kullanım bulabilirsiniz: <BR> man bash<BR> tkinfo bash<BR> (Ben standart info gezgininden nefret ediyorum, ancak <A href= "http://math-www.uni-paderborn.de/~axel/tkinfo/">tkinfo</A> veya konqueror (url için info:/bash/Top ) oldukça iyidir)</LI> <LI>LinuxFocus'un <A href= "../November2000/article131.shtml">GNU dosya araçları</A> yazısı.</LI> <LI>LinuxFocus'un <A href= "../July1998/article53.html">Düzenli yapılar</A> yazısı.</LI> <LI>LinuxFocus'un <A href= "../September1999/article103.html">AWK</A> yazısı.</LI> <LI>LinuxFocus'un <A href= "../November1998/article68.html">Temel UNIX komutları</A> yazısı</LI> <LI>Eğer, sisteminizde bash yüklü değil ise, veya son sürümünü elde etmek istiyorsanız, GNU'nun sanaldoku yöresinden (http://www.gnu.org) elde edebilirsiniz(Sisteminizde bash olup olmadığını anlamak için bash komutunu çalıştırınız. Eğer, herhabgi bir hatayla karşılaşmıyorsanız, o zaman bash kabuğu yüklü demektir.)</LI> </UL> <!-- vim: set sw=2 ts=2 et: --> <!-- 2pdaIgnoreStart --> <A NAME="talkback"> </a> <h2>Bu yazı için görüş bildiriminde bulunabilirsiniz</h2> Her yazı kendi görüş bildirim sayfasına sahiptir. Bu sayfaya yorumlarınızı yazabilir ve diğer okuyucuların yorumlarına bakabilirsiniz. <center> <table border="0" CELLSPACING="2" CELLPADDING="1"> <tr BGCOLOR="#C2C2C2"><td align=center> <table border="3" CELLSPACING="2" CELLPADDING="1"> <tr BGCOLOR="#C2C2C2"><td align=center> <A href="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=216&lang=en"><b> talkback page </b></a> </td></tr></table> </td></tr></table> </center> <HR size="2" noshade> <!-- ARTICLE FOOT --> <CENTER><TABLE WIDTH="95%"> <TR><TD ALIGN=CENTER BGCOLOR="#9999AA"> <A HREF="../../common/lfteam.html">Görselyöre sayfalarının bakımı, LinuxFocus Editörleri tarafından yapılmaktadır</A> <BR><FONT COLOR="#FFFFFF">© Katja and Guido Socher, <a href="../../common/copy.html">FDL</a> <BR><a href="http://www.linuxfocus.org">LinuxFocus.org</a></FONT> <BR><a href="http://cgi.linuxfocus.org/cgi-bin/lfcomment?lang=tr&article=article216.shtml" target="_TOP">Burayı klikleyerek hataları rapor edebilir ya da yorumlarınızı LinuxFocus'a gönderebilirsiniz</A><BR></TD> <TD BGCOLOR="#9999AA"><!-- TRANSLATION INFO --> <font size=2>Çeviri bilgisi:</font><TABLE> <tr><td><font size=2>en</font></td> <td><font size=2>-></font></td> <td><font size=2>--</font></td> <td><font size=2><a href="mailto:katja@linuxfocusorg, guido@linuxfocus.org"><FONT COLOR="#FFFFFF">Katja and Guido Socher</FONT></a></font></td> </tr> <tr><td><font size=2>en</font></td> <td><font size=2>-></font></td> <td><font size=2>tr</font></td> <td><font size=2><a href="mailto:ceyhun.elmas@linuxfocus.org, erdal@linuxfocus.org"><FONT COLOR="#FFFFFF">Ceyhun ELMAS ve Erdal MUTLU</FONT></a></font></td> </tr> </TABLE></TD> </TR></TABLE></CENTER> <p><font size=1>2001-09-17, generated by lfparser version 2.17</font></p> <!-- 2pdaIgnoreStop --> </BODY> </HTML>