@ARGV in Perl
Eğer bir Perl scripti yazdi iseniz, mesela adı programming.pl olsun, kullanıcılar komut satırından perl programming.pl komutunu kullanarak çalıştırabilirler .
Ayrica şu şekilde komut satırı argümanları gecebilirler. perl programming.pl -a --machine remote /etc.
Kullanıcıların bu şekilde parametre girmesini kimse engelleyemez fakat script bu değeleri önemsemeyecektir. Bu durumda soru şu, programcı kişi, eğer değer geçilmiş ise bu değerleri nasıl bilecek?
Komut satırı
Perl otomatik olarak adı @ARGV olan, komut satırından girilen değerleri tutan bir dizi sağlar. Bu değişkeni tanımlamak zorunda değilsiniz, hatta use strict ifadesi kullanılmışsa bile.
Bu değişken her zaman vardır ve komut satırından girilen değerleri tutar .
Eğer parametre yok ise, dizi boş olacaktır. Komut satırından girilen bir parametre var ise, o değer @ARGV dizisinin tek elemanı olacaktır. Yukarıdaki örnekte @ARGV dizisi aşağıdaki elemanları içerir: -a, --machine, remote, /etc
Şimdi bunu pratikte görelim:
Aşağıdaki kodu programmimg.pl olarak kaydedin.
use strict; use warnings; use Data::Dumper qw(Dumper); print Dumper \@ARGV;
Şu şekilde çalıştırın: perl programming.pl -a --machine remote /etc çıktı şu olacaktır:
$VAR1 = [ '-a', '--machine', 'remote', '/etc' ];
Göreceğiniz üzere @ARGV dizisinin içeriğini basmak için Data::Dumper kütüphanesinin Dumper fonksiyonunu kullandık.
Eğer başka bir programlama dilinden geliyor iseniz, aşağıdaki soruyu merak ediyor olabilirsiniz: Perl programının adı nerede?
Scriptin adı $0 değişkeni içindedir
Çalıştırılan programın adı, yukarıdaki örnekte programming.pl, her zaman $0 adlı Perl değişkeni içindedir. (Lutfen, $1, $2, vs. gibi tanımlamaların ilişkili olmadığını not ediniz)
C programcısı
Eğer C programlama dili biliyor iseniz, bu size argv ile benzer gelecektir, tek farkı Perl'deki @ARGV dizisi program adını içermez. Script adı $0 değişkeninde tutulur. Ayrıca argc gibi bir değişkene gerek yoktur, çünkü @ARGV dizisindeki eleman sayısını scalar fonksiyonunu kullanarak veya dizinin scalar içeriğini alarak kolayca alabilirsiniz.
Unix/Linux Kabul Programlama
Eğer Unix/Linux Shell programlama dünyasindan geliyor iseniz, $0 değişkeninin burada da script adi olduğu size tanıdık gelecektir. Kabuk programlada ayrıca $1, $2, vs. diğer komut satırı parametrelerini tutar. Bu değişkenler Perl dilinin düzenli ifadeler (regular expressions) konusunda kullanılır. Komut satırı argumanları @ARGV dizisinde tutulur. Benzer şekilde $* ifadesi Unix/linux kabuk programlamada kullanılır
@ARGV dizisinden komut satırı argümanlarına nasıl erişilir
@ARGV diğer diziler gibi Perl'de bir dizidir. Programcı tarafından oluşturulan dizilerden tek farkı, tanımlamaya gerek olmayışı ve program başladığında Perl tarafından dolduruluşudur.
Bu durum dışında, normal dizi gibi ele alınabilir. foreach kullanarak elemanları uzerinde gezebilir, veya indeks kullanarak elemanlara teker teker erişebilirsiniz: $ARGV[0].
Ayrıca dizi üzerindeshift, unshift, pop or push komutlarını kullanabilirsiniz.
Aslında, @ARGV dizisinin sadece içeriğini görüntülemekle kalmayıp, içeriğini de değiştirebilirsiniz.
Komut satırında tek bir değer bekliyor iseniz bu değerin ne olduğunu kontrol edebilir, ya da $ARGV[0] değerine bakarak geçerli olup olmadığını anlayabilirsiniz. 2 değişken bekliyor iseniz $ARGV[1] değerine de bakarsınız.
Örnek olarak bir telefon defteri oluşturalım. Bir isim girildiğinde, uygulama isme karşılık gelen numarayı ekrana basacak. İsim ve numara girilir ise program bu ikiliyi "veritabanı"na kaydedecek. (Kodun veritabanı ile ilgili kısmını ele almayacağız, işlem yapılmış varsayacağız.)
Parametrelerin $ARGV[0] içinde ve belki ayrıca $ARGV[1] içinde tutulacağını, ama diğer elemanların bir anlam ifade etmediğini biliyoruz. $ARGV[0] and benzeri değişkenler yerine kendi adlandırdığınız değişkenleri kullanmak her zaman daha iyidir. Bu nedenle yapmak isteyeceğimiz ilk iş dizi değerlerini oluşturduğumuz değişkenlere kopyalamak:
Aşağıdaki çalışan bir kod:
my $name = $ARGV[0]; my $number = $ARGV[1];
Fakat aşağıdaki çok daha hoş:
my ($name, $number) = @ARGV;
Şimdi tüm örneği görelim (veritabanı kısmı hariç). Aşağıdaki kodu programming.pl olarak kaydedin.
use strict; use warnings; my ($name, $number) = @ARGV; if (not defined $name) { die "Need name\n"; } if (defined $number) { print "Save '$name' and '$number'\n"; # save name/number in database exit; } print "Fetch '$name'\n"; # look up the name in the database and print it out
Değerleri @ARGV dizisinden kopyaladıktan sonra, isim girilip girilmediğini kontrol ediyoruz. Eğer girilmemiş ise, ekrana bir hata mesajı basacak ve scriptten çıkacak olan die komutunu çağırıyoruz.
Eğer isim var ise, numarayı kontrol ediyoruz. Eğer numara var ise veritabanına kaydediyor (yukarıda ele alınmadı) ve scriptten çıkıyoruz.
Numara yok ise veritabanindan isim bilgisini çekmeye çalışıyoruz. (Bu kısım da yukarıda ele alınmadı.)
Şimdi nasıl çalıştığına bakalım: ($ işareti komut satırından gelmektedir, biz bunu yazmayacağız.)
$ perl programming.pl Foo 123 Save 'Foo' and '123' $ perl programming.pl Bar 456 Save 'Bar' and '456' $ perl programming.pl John Doe 789 Save 'John' and 'Doe'
Ilk iki çağrı OK ama sonuncusu iyi gözükmüyor. "John Doe"'nun telefon numarasını 789 olarak kaydetmek istedik, ama scriptimiz bunun yerine "John"'un telefon numarasını "Doe" olarak kaydetti.
Sebep basit, ve Perl ile yapılacak bir şey bulunmamakta. Bu çağrı diğer herhangi bir dilde de bu şekilde çalışacaktı. Scripti çalıştırdığınız kabuk veya komut satırı, çalıştırma komutunu ayırır ve değerleri @ARGV dizisine koyması için Perl'e geçirir. Hem Unix/Linux kabuk ve Windows Komut Satırı program calistirma kodundan sonraki ifadeleri boşluğu baz alarak ele alır. Bu nedenle perl programming.pl John Doe 789 şeklinde çağrı yaptığımızdan, 3 parametre scriptimize geçirildi. Doğu çalışmasını sağlamak için çift tırmak içinde boşluk kullanılabilir:
$ perl a.pl "John Doe" 789 Save 'John Doe' and '789'
Siz, programcı olarak bundan daha fazlasını yapamazsınız.
Argümanları kontrol etmek
Bazen girilen arguman sayısının beklediğiniz sayıyı aşıp aşmadığını kontrol edebilirsiniz. Bu kullanıcının yukarıdaki hatayı yapmasını engeller, ama ya kullanıcı John Doe'nun telefon numarasını almak ister ve çift tırnakları unutursa:
perl a.pl John Doe Save 'John' and 'Doe'
Bu durumda parametre sayısı dogru rakam olan 2'dir.
Bu durumda da, küçük bir geliştirme yapıp $number değişkeninin içeriğinin telefon numarası olarak kabul edilebilecek formatta olup olmadığını kontrol edebilirsiniz. Bu hata olasılığını azaltacaktır. Fakat hala kusursuz ve evrensel bir çözüm olmayacaktır: Başka uygulamalarda birçok sayıda aynı kısıtlarda parametreler olabilir.
Maalesef @ARGV dizisini "manual" ayrıştırırken yapabileceğimiz fazla şey yok. Bir başka makalede Getopt::Long ve hayatımızı daha kolaylaştıran benzer kütüphanelere değineceğiz, şimdi bir başka basit durumu görelim.
tek bir parametreyi shift etmek
Kullanıcının komut satırından bir dosya adı gireceğini varsayalım Bu durumda aşağıdaki kodu yazarsınız:
my $filename = shift or die "Usage: $0 FILENAME\n";
Daha kolay açıklayabilmek için kodu 2 bölüme ayıralım:
my $filename = shift
Normal şartlarda shift parametre olarak bir dizi alır ama bu ornekte parametresiz kullandık. Bu gibi durumlarda shift komutu @ARGV dizisi üzerinde çalışır. Bu nedenle yukarıdaki kod @ARGV dizisinin birinci değerini $filename değişkenine atar. (En azından kod bir subroutine içinde değilse.)
Bu durumda aşağıdaki koda sahip oluruz: $filename or die "Usage: $0 FILENAME\n"
Bu boolean bir ifadedir. Eğer $filename değişkeni dosya adını içeriyor ise True olarak düşünülecek ve script or die ... bölümünü çalıştırmadan çalışmaya devam edecektir. Diğer taraftan, eğer @ARGV dizisi boş ise, $filename undef olarak tanımlanacak, False yorumlanacak ve Perl sağ tarafta yer alan or durumunu çalıştıracağından, ekrana bir mesaj basıp, scriptten çıkacaktır.
Etkileyici biçimde, bu kod parçası komut satırından bir değer girilip girilmediğini kontrol eder. Değer $filename değişkenine kopyalanır. Değer yok ise, script die komutu ile sonlanır.
Küçük bir bug
Yukarıdaki kodda küçük bir bug bulunmakta. Kullanıcı dosya adı olarak 0 değerini girerse. Yine False olarak işlem görecek ve script bu dosyaya işlem yapmayı reddedecektir. Soru şu: Bu çok önemli mi? Kodumuzun dosya adı 0 olan bir dosyaya işlem yapmaması ihtimalini göze alabilir miyiz... ?
Kompleks durumlar
Yukarıdaki bir veya iki parametreli durumlardan cok daha kompleks başka durumlar da mevcuttur. Bu gibi durumlar için büyük ihtimalle Getopt::Long gibi ne tür parametreleri kabul edeceğinize bağlı olarak @ARGV dizisinin içeriğini analiz edebilecek araçlar kullanmak isteyeceksiniz.
Published on 2013-12-10