Yeniden yönlendirme başarısız olursa Bash programı yürütülmedi


9

Bash'da, yeniden yönlendirme kullanan bir komut başarısız olursa, bundan önce çalışan programların çalışmadığını fark ettim.

Örneğin, bu program "a" dosyasını açar ve "a" dosyasına 50 bayt yazar. Ancak, bu komutu yetersiz izinlere (~ root / log) sahip bir dosyaya yeniden yönlendirmeyle çalıştırmak, "a" dosya boyutunda herhangi bir değişiklik sağlamaz.

$ ./write_file.py >> ~root/log
-bash: /var/root/log: Permission denied
cdal at Mac in ~/experimental/unix_write
$ ls -lt
total 16
-rw-rw-r--  1 cdal  staff  0 Apr 27 08:54 a <-- SHOULD BE 50 BYTES

Biri programın çalışacağını, herhangi bir çıktıyı yakalayacağını (ama aynı zamanda "a" dosyasına yazdığını) düşünür ve sonra ~ root / log dosyasına herhangi bir çıktı yazamaz. Bunun yerine program asla çalıştırılmaz.

Bu neden ve bash bir programı yürütmeden önce gerçekleştirdiği "denetimlerin" sırasını nasıl seçiyor? Başka kontroller de yapılıyor mu?

ps "izin reddedildi" dosyasına yönlendirildiğinde cron altında çalışan bir programın gerçekten çalışıp çalışmadığını belirlemeye çalışıyorum.


Her şey iyi çalışıyor (yani .py dosyanızın sahiplik ve izinleri) programınız iyi çalışıyor. Sorunlarınız yönlendirmeden geliyor. Bir filein / root dizini yazma izniniz yok. Ve stdouttam olarak bunu yapmak için yönlendirme yaptınız . Yani, programınız çalışsa bile herhangi bir çıktı görmeyeceksiniz.
MelBurslan

2
Mel, bu doğru değil, program aslında hiç çalışmadı. Aşağıdaki cevaplara bakın.
Charlie Dalsass

Siz: " write_file.pyProgramı çalıştırın ve çıktısını ~root/logbash'a gönderin :" Maalesef bu dosyaya yazmanıza izin verilmiyor! "Kabuk tam olarak ne yapması gerekiyorsa. İstediğiniz şeyi yapamazsa yapmak, neden bir sorun olduğunu hemen size bildirir, bununla nasıl başa çıkacağınıza karar verme fırsatı verir.Tüm bash koruyucular için, bu komutu çalıştırırsanız ve çıkışı kaydetmezseniz Çok Kötü Şeyler olabilir. Kaydetmek için bir yer belirlediyseniz yeterince önemli olsaydı, ASS | U | ME stdout'u kaydetmeden koşmanın sorun olmadığını
Monty Harder

Yanıtlar:


18

Bu gerçekten çek sipariş etme meselesi değil, sadece kabuğun işleri kurduğu sıra. Yönlendirmeler komut çalıştırılmadan önce ayarlanır; bu nedenle, örneğinizde, kabuk, ~root/logilgili herhangi bir şey yapmaya çalışmadan önce ekleme için açmaya çalışır ./write_file.py. Günlük dosyası açılamadığından, yönlendirme başarısız olur ve kabuk komut satırını o noktada işlemeyi durdurur.

Bunu göstermenin bir yolu, yürütülebilir olmayan bir dosya alıp çalıştırmayı denemektir:

$ touch demo
$ ./demo
zsh: permission denied: ./demo
$ ./demo > ~root/log
zsh: permission denied: /root/log

Bu, kabuğun ./demoyeniden yönlendirme ayarlanamadığında bile bakmadığını gösterir .


Wow, bu kadar basit mi? Önce yeniden yönlendirmelerin yapıldığını fark etmedim. Bu cevap ve diğer harika cevaplar için de teşekkürler.
Charlie Dalsass

6
İlk yapılmazlarsa, çıktı nereye yazılır?
Charles Duffy

Çıktı yazılamıyorsa, komutu çalıştırmanın güvenli olduğunu nasıl bilebiliriz? Belki de komut, bir veri deposundan silinmekte olan bilgileri verir ve çıktının yakalanması kesinlikle gereklidir. İyi bir şey, bu izinleri düzeltene kadar bash'ın çalışmasına izin vermez, değil mi?
Monty Harder

11

Gönderen bash adam sayfasında, bölüm REDIRECTION (bana göre vurgu):

Bir komut yürütülmeden önce , girişi ve çıkışı kabuk tarafından yorumlanan özel bir gösterimle yeniden yönlendirilebilir.

...

Dosya açılamıyor veya oluşturulamıyorsa, yeniden yönlendirme başarısız oluyor.

Kabuk için stdoutbaşarısız olan hedef dosyayı açmaya çalışır ve komut hiç çalıştırılmaz.


Çok teşekkürler. Keşke sayfanın "... çıktı yeniden yönlendirilemezse, program yürütülmeyecek" ile biraz açıklığa kavuşmasını isterdim.
Charlie Dalsass

Güncellenmiş; aşağıdaki bazı paragraflar gizlidir.
Murphy

Aslında oldukça açık. "Dosya açılamıyor veya dosya oluşturulamıyorsa, yönlendirme başarısız oluyor." İşte burada. Tekrar teşekkürler.
Charlie Dalsass

3

Kabuğun programa başlamadan önce yeniden yönlendirmeler yapması gerektiğini gözlemlemekte fayda var .

Örneğinizi düşünün:

./write_file.py >> ~root/log

Kabukta ne olur:

  1. Biz (kabuk) fork(); alt işlem, açık dosya tanımlayıcılarını üst öğesinden (kabuk) devralır.
  2. Alt süreçte, biz fopen()"~ root / log" u genişletiyoruz ve dup2()fd 1'e (ve close()geçici fd'ye). Eğer fopen()başarısız çağrı exit()ebeveyne hatayı bildirmek.
  3. Hala çocukta, exec()"./write_file.py" diyoruz. Bu işlem artık kodlarımızdan hiçbirini çalıştırmıyor (yürütülemediğimiz sürece, bu durumda exit()hatayı üst öğeye bildireceğiz).
  4. Ebeveyn wait(), çocuğun sonlandırmasını ve çıkış kodunu ( $?en azından içine kopyalayarak) işlemesini sağlar .

Yönlendirme arasındaki çocukta gerçekleşmesi gereken Yani fork()ve exec(): Daha önce de oldu edemez fork()o kabuk stdout'u değişmez gerektiğinden ve bu sonra olamaz exec()dosya adı ve kabuk yürütülebilir kod artık Python program tarafından almıştır çünkü . Ebeveynin, çocuğun dosya tanımlayıcılarına erişimi yoktur (ve yapsa bile, exec()stdout'a ilk yazma ile yeniden yazma arasında yeniden yönlendirmeyi garanti edemez ).


0

Bunun tam tersi olduğunu bildirdiğim için üzgünüm. Kabuğun önce G / Ç'yi açması ve ardından kontrolü programa geçirmesi gerekir.

tee bu durumda yararlı olabilir: ./write_file.py | tee -a ~root/log > /dev/null


Tee başarısız olduktan sonra Python senaryosu SIGPIPE'de ölmeyecek mi?
Kevin

Yaptığım teste göre değil ama denemenizi öneririm.
Julie Pelletier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.