Dalam bash, saya perhatikan bahwa jika perintah menggunakan pengalihan akan gagal, program apa pun yang berjalan sebelum itu tidak dijalankan.
Misalnya, program ini membuka file "a" dan menulis 50 byte ke file "a". Namun, menjalankan perintah ini dengan pengalihan ke file dengan izin tidak mencukupi (~ root / log), tidak menghasilkan perubahan dalam ukuran file "a".
$ ./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
Orang akan berpikir program akan berjalan, menangkap output apa pun (tetapi juga menulis ke file "a"), dan kemudian gagal menulis output apa pun ke ~ root / log. Sebaliknya program tidak pernah berjalan.
Mengapa demikian, dan bagaimana bash memilih urutan "cek" yang dijalankannya sebelum menjalankan suatu program? Apakah pemeriksaan lain dilakukan juga?
ps Saya mencoba untuk menentukan apakah suatu program yang dijalankan di bawah cron benar-benar berjalan ketika diarahkan ke file "izin ditolak".
sumber
stdout
untuk melakukan hal itu. Jadi, Anda tidak akan melihat output apa pun, meskipun program Anda berjalan.write_file.py
program dan kirim hasilnya ke~root/log
bash:" Maaf, tetapi Anda tidak boleh menulis ke file itu! "Shell melakukan apa yang seharusnya dilakukan. Jika tidak bisa melakukan apa yang Anda minta lakukan, itu segera memberitahu Anda mengapa ada masalah, memberi Anda kesempatan untuk memutuskan bagaimana menghadapinya. Untuk semua pemilik bash tahu, Hal-hal yang Sangat Buruk bisa terjadi jika Anda menjalankan perintah itu dan tidak bisa menyimpan output. Jika itu cukup penting, Anda menentukan tempat untuk menyimpannya, itu akan salah bagi ASS | U | ME, itu OK untuk berjalan tanpa menyimpan stdout.Jawaban:
Ini sebenarnya bukan masalah memesan cek, hanya urutan di mana shell mengatur segalanya. Pengalihan diatur sebelum perintah dijalankan; jadi pada contoh Anda, shell mencoba membuka
~root/log
untuk menambahkan sebelum mencoba melakukan apa pun yang melibatkan./write_file.py
. Karena file log tidak dapat dibuka, pengalihan gagal dan shell berhenti memproses baris perintah pada saat itu.Salah satu cara untuk menunjukkan ini adalah dengan mengambil file yang tidak dapat dieksekusi dan mencoba menjalankannya:
Ini menunjukkan bahwa shell bahkan tidak melihat
./demo
ketika pengalihan tidak dapat diatur.sumber
Dari halaman bash man, bagian REDIRECTION (penekanan oleh saya):
Jadi shell mencoba untuk membuka file target
stdout
, yang gagal, dan perintah tidak dijalankan sama sekali.sumber
Patut diperhatikan bahwa shell harus membuat pengalihan sebelum memulai program.
Pertimbangkan contoh Anda:
Apa yang terjadi di shell adalah:
fork()
; proses anak mewarisi deskriptor file terbuka dari induknya (shell).fopen()
(perluasan) "~ root / log", dandup2()
ke fd 1 (danclose()
fd sementara). Jikafopen()
gagal, panggilexit()
untuk melaporkan kesalahan kepada orang tua.exec()
"./write_file.py". Proses ini sekarang tidak lagi menjalankan kode kami (kecuali kami gagal mengeksekusi, dalam hal ini kamiexit()
melaporkan kesalahan kepada orang tua).wait()
anak untuk mengakhiri, dan menangani kode keluarnya (dengan menyalinnya$?
, setidaknya).Jadi pengalihan harus terjadi pada anak antara
fork()
danexec()
: itu tidak dapat terjadi sebelumnyafork()
karena tidak boleh mengubah stdout shell, dan itu tidak dapat terjadi setelahexec()
karena nama file dan kode executable shell sekarang telah digantikan oleh program Python . Orang tua tidak memiliki akses ke deskriptor file anak (dan bahkan jika itu, tidak dapat menjamin untuk mengalihkan antaraexec()
dan menulis pertama ke stdout).sumber
Saya minta maaf untuk memberi tahu Anda bahwa itu justru sebaliknya. Shell perlu membuka I / O terlebih dahulu dan kemudian melewati kontrol ke program.
tee
mungkin terbukti bermanfaat dalam kasus ini:./write_file.py | tee -a ~root/log > /dev/null
sumber