2011-12-16 12 views
7

Perl betiğimi hangi betik, program veya kabuktan çalıştırdığımı nasıl belirlerim?Perl betiğimde hangi komut dosyasının, programın veya kabuğun çalıştırıldığını nasıl öğrenebilirim?

Örnek: Kabuktan (her kabuk türü için özelleştirilmiş), başka bir perl komut dosyasından komut dosyası olarak çağrılırsa farklı bir çıktı türü ve çalıştırılırsa makine tarafından okunabilir bir biçim varsa, insan tarafından okunabilir çıktısına sahip olmak isteyebilirim Sürekli bütünleştirme sunucusu gibi bir program.

Motivasyon: Çıktısını hangi kabuğun üzerine uygulayarak değiştiren bir aracım var. Normalde bu davranışı senaryo için bir seçenek olarak uyguluyorum, ancak bu aracın tasarımı seçeneklere izin vermiyor. Diğer kabuklar, hangi kabuğun çalıştığını gösteren ortam değişkenlerine sahiptir. Böyle bir özel değişkeni olmayan Powershell'i desteklemek için bir yama üzerinde çalışıyorum. Düzenleme: Bu yanıtların birçoğu Linux'a özeldir. Maalesef, Powershell Windows içindir. getppid, $ENV{SHELL} değişkeni ve ps'a bildirme bu durumda yardımcı olmaz. Bu betiğin çapraz platform çalıştırması gerekiyor.

+0

Anladığımdan emin değilim - bu durumda ebeveyn işlemine bakmamalısınız? – x0n

+0

STDOUT'un bir terminal ('-t') olup olmadığını ve eğer öyleyse, sürekli bir entegrasyon daemonundan ziyade etkileşimli bir kabuktan çağrıldığınızı varsayarak test edebilirsiniz. Bununla birlikte, bu ortak teknik, ayrı-olası-ebeveyn-başına çıktıyı özelleştirmek için konuşmaz (ama bence bu yanlış bir arzu, her neyse). – pilcrow

+0

Unutmayın, normalde kabuk veya kullanıcının hangi kabuğun çalıştığını belirtmesi için ayarladığı bir ortam değişkenini arar; Powershell ile böyle bir ortam değişkeni yoktur. –

cevap

1

Ortamınıza bağlı olarak, ortam değişkenlerinden alabilirsiniz. Aşağıdaki kodu düşünün: benim Ubuntu sisteminde

/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);' | grep sh 

, beni alır:

'SHELL' => '/bin/bash', 

Yani ben bir bash kabuğundan Perl kullandığımı söyleyen sanırım. Başka bir şey kullanırsanız, SHELL değişkeni size bir ipucu verebilir.

Ama şunu söyleyeyim ki bash içinde olduğunuzu, ancak perl'in bir alt kabuktan yürütüldüğünü. ki bu da, aynı zamanda kabuk veya komut mutlak dosya adını göstermek değişken $_ yürütülmektedir

 '_' => '/bin/sh', 
     'SHELL' => '/bin/bash', 

Yani kabuk hala bash, ancak bash vardır:

/bin/sh -c "/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);'" | grep sh 

Sen bulacaksınız: Sonra denemek ayrıca değerli bir ipucu verir. Benzer olarak, diğer ortamlar için muhtemelen size değerli ipuçları vermelidir perl %ENV hash içinde ipuçları olacaktır.

+0

Ah, nihayet neden düştüğümü anladım. Şu ana kadar powershell etiketini görmedim. Benim hatam. –

+0

Seni reddeden ben değildim, ama powershell'nin çalıştığını söylemek için bir ortam değişkenine bayılıyorum. Ne yazık ki, Powershell'in böyle bir değişkeni yok. Komut, diğer kabuk türleri için çıktının ne olacağını belirlemek için ortamı kullanır. –

+0

http://vlaurie.com/computers2/Articles/environment-variables-windows-vista-7.htm Burada, varsayılan olarak cmd.exe'ye COMSPEC noktaları gibi görünüyor; PowerShell altında çalışırken PowerShell uygulamasına işaret edebilir mi? Eğer öyleyse, Cygwin ve benzerleri de dahil olmak üzere ortamdan çalışma ortamı bulmak mümkün olmalıdır ... –

5

getppid() kullanıyorsunuz. child.pl bu pasajı atın: komut satırından çalıştırmak durumunda

my $ppid = getppid(); 
system("ps --no-headers $ppid"); 

, system (diğer şeylerin yanı sıra) bash veya benzeri gösterecektir. Başka bir komut dosyasında system("perl child.pl"); ile çalıştırın, ör. parent.pl ve perl parent.pl uygulamasının bunu gerçekleştirdiğini göreceksiniz.

argümanlarla sürecin sadece adını yakalamak için (teşekkürler doğru ps sözdizimi için Ikegami için):

my $ppid = getppid(); 
my $ps = `ps --no-headers -o cmd $ppid`; 
chomp $ps; 

DÜZENLEME: Bu yaklaşıma bir alternatif yumuşak bağlantıları oluşturmak için olabilir senin Komut dosyası, farklı bağlamların komut dosyasına erişmek için farklı bağlantılar kullanmasını sağlayın ve bunun etrafında mantık oluşturmak için $0 inceleyin.

+2

Biraz daha güvenilir: 'chomp ($ parent_name = \' ps --no-headers -o cmd $ ppid \ ');' – ikegami

+0

@ikegami: Teşekkürler. :) Bu formatı belirtmek için nasıl gideceğimi bilmiyordum. – flesk

+0

Ne yazık ki, Windows'da Perl 'getppid()' i desteklemiyor ya da 'ps' olasılığını dışarda tutuyor. :( –

3

Amacınızı gerçekleştirmek için farklı bir yaklaşım öneririm.Bağlamında tahmin etmek yerine, onu daha açık bir hale getirin. Her kullanım durumu tamamen ayrıdır, dolayısıyla üç farklı arayüze sahiptir.

  1. Perl programında çağrılabilen bir işlev. Bu muhtemelen bir Perl veri yapısı döndürür. Bu, komut çıktısını ayrıştırmaktan çok daha kolay, daha hızlı ve daha güvenilirdir. Ayrıca betiklerin temeli olarak da hizmet edecektir.

  2. Geçerli kabuk için çıktı veren bir komut dosyası. Hangi kabuğun çalıştığını öğrenmek için $ENV{SHELL}'a bakabilirsiniz. Bonus puanlar için, açıkça geçersiz kılmak için bir anahtar verin.

  3. Sürekli entegrasyon sunucunuz gibi Perl olmayan bir program içinde çağrılabilen ve makine tarafından okunabilir çıktı veren bir komut dosyası. XML ve/veya JSON ya da her neyse.

2 ve 3 veri Herbirinin kendi özel ihtiyaçlarını karşılayan hazırlanmıştır 1.

çıkan biçimlendirmek için sadece ince sargı olacaktır. Her biri buluşsal olmadan çalışır. Her biri bağlamı ve kullanıcının ne istediğini tahmin etmeye çalışmaktan çok daha basit olacaktır.

2 ve 3'ü ayıramazsanız, sürekli tümleştirme sunucusunun bir ortam değişkeni ayarlayıp onu aramasını sağlayın.

+0

Anlaştık. Bahsettiğim gibi, yukarıdakiler bu tekniğin olası uygulamalarının sadece örnekleridir. Bu durumda, betik bir kabuk betiği çıkarır ve diğer araçlar, betiği çağıran kabuk için doğru türdeki kabuk betiğini yayımlamasını bekler. Hemen hemen tüm diğer kabuklar için, hangi kabuğun kullanılacağını belirten ortam değişkenleri vardır. Powershell böyle bir değişken vermez. –

1

Bu, Windows XP'de PowerShell v2.0 ile çalışır, bu yüzden bir tane tuzla alın. Bir cmd.exe kabuğunda

, alıyorum: PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\

PowerShell konsol penceresinde, ben olsun oysa: E:\Home\user nerede "Belgelerim" klasörü olduğu

PSModulePath=E:\Home\user\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsP owerShell\v1.0\Modules\

olduğunu. Yani, bir sezgisel PSModulePath kullanıcı bağımlı bir yol içerip içermediğini kontrol etmek olabilir.

ek olarak, bir konsol penceresinde, alıyorum:

!::=::\

ortamda. PowerShell İMKB, ben alıyorum:

!::=::\ 
!C:=C:\Documents and Settings\user
+0

+1 - Ah, saçma. Cevabını bile fark etmedim. Ben de aynı şeyi anladım. Bu arada, powershell 1.0 değil - v1 modülleri desteklemiyor. % Windir% altındaki yol, v1, v2 ve v3 powershell için v1.0'dır. – x0n

1

Yukarıdaki PowerShell 2.0 ya da (büyük olasılıkla) çalıştıran ediyorsanız %psmodulepath% değişken ortam inceleyerek bir ebeveyn süreç olarak kabuk çıkarabiliriz. Varsayılan olarak, %windir%\system32\windowspowershell\v1.0\modules altındaki sistem modüllerine işaret eder; Bu değişkeni cmd.exe'dan incelediğinizde görürsünüz.

Ancak, PowerShell başlatıldığında, kullanıcının varsayılan modül arama yolunu aşağıdaki gibi görünen bu ortam değişkenine önceden ekler: %userprofile%\documents\windowspowershell\modules. Bu, çocuk süreçleri tarafından miras alınır. Bu nedenle, mantığınız,% psmodulepath% 'in powershell 2.0 veya üstünü algılamak için% userprofile% ile başlayıp başlamadığını test etmek olacaktır. Bu, PowerShell 1.0'da çalışmaz çünkü modülleri desteklemez.

İlgili konular