Ketika Anda mengarahkan ulang daftar perintah yang berisi pengalihan exec, exec> / dev / null tampaknya tidak akan diterapkan setelahnya, seperti dengan:
{ exec >/dev/null; } >/dev/null; echo "Hi"
"Hai" dicetak.
Saya mendapat kesan bahwa {}
daftar perintah tidak dianggap sebagai subkulit kecuali itu adalah bagian dari pipa, jadi exec >/dev/null
seharusnya masih diterapkan dalam lingkungan shell saat ini dalam pikiran saya.
Sekarang jika Anda mengubahnya ke:
{ exec >/dev/null; } 2>/dev/null; echo "Hi"
tidak ada output seperti yang diharapkan; deskriptor file 1 tetap menunjuk / dev / null untuk perintah selanjutnya juga. Ini ditunjukkan oleh rerunning:
{ exec >/dev/null; } >/dev/null; echo "Hi"
yang tidak akan memberikan hasil.
Saya mencoba membuat skrip dan menggantinya, tetapi saya masih tidak yakin persis apa yang terjadi di sini.
Pada setiap titik dalam skrip ini, apa yang terjadi pada deskriptor file STDOUT?
EDIT: Menambahkan output strace saya:
read(255, "#!/usr/bin/env bash\n{ exec 1>/de"..., 65) = 65
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
close(10) = 0
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
dup2(10, 1) = 1
fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, TCGETS, 0x7ffee027ef90) = -1 ENOTTY (Inappropriate ioctl for device)
write(1, "hi\n", 3) = 3
sumber
close(10)
. Bisakah Anda juga memposting seluruh konten skrip tempat Anda menjalankan strace?;
setelah}
, yang mengubah arti> /dev/null
untuk tidak berlaku untuk daftar majemuk{}
setelah semua.Jawaban:
Ayo ikuti
selangkah demi selangkah.
Ada dua perintah:
Sebuah.
{ exec >/dev/null; } >/dev/null
, diikuti olehb.
echo "Hi"
Shell pertama-tama mengeksekusi perintah (a) dan kemudian perintah (b).
Pengerjaan
{ exec >/dev/null; } >/dev/null
hasil sebagai berikut:Sebuah. Pertama, shell melakukan pengalihan
>/dev/null
dan ingat untuk membatalkannya ketika perintah berakhir .b. Kemudian, shell dieksekusi
{ exec >/dev/null; }
.c. Akhirnya, shell mengganti output standar kembali ke posisi semula. (Ini adalah mekanisme yang sama seperti in
ls -lR /usr/share/fonts >~/FontList.txt
-redirections dibuat hanya selama durasi perintah.)Setelah perintah pertama selesai, shell mengeksekusi
echo "Hi"
. Output standar adalah dimanapun itu sebelum perintah pertama.sumber
Agar tidak menggunakan sub-shell atau sub-proses, ketika output daftar senyawa
{}
disalurkan>
, shell menyimpan deskriptor STDOUT sebelum menjalankan daftar senyawa dan mengembalikannya setelah. Jadi,exec >
dalam daftar majemuk tidak membawa efeknya melewati titik di mana deskriptor lama dipulihkan sebagai STDOUT.Mari kita lihat bagian yang relevan dari
strace bash -c '{ exec >/dev/null; } >/dev/null; echo hi' 2>&1 | cat -n
:Anda dapat melihat bagaimana, pada baris 134, deskriptor
1
(STDOUT
) disalin ke deskriptor lain dengan indeks setidaknya10
(itulah yangF_DUPFD
dilakukannya; ia mengembalikan deskriptor terendah yang tersedia mulai dari angka yang diberikan setelah menggandakan ke deskriptor itu). Juga lihat bagaimana, pada baris 137, hasilopen("/dev/null")
(deskriptor3
) disalin ke deskriptor1
(STDOUT
). Akhirnya, on line147
, yang lamaSTDOUT
disimpan pada deskriptor10
disalin kembali ke deskriptor1
(STDOUT
). Efek bersih adalah untuk mengisolasi perubahan keSTDOUT
online144
(yang sesuai dengan bagian dalamexec >/dev/null
).sumber
exec
.Perbedaan antara
{ exec >/dev/null; } >/dev/null; echo "Hi"
dan{ exec >/dev/null; }; echo "Hi"
adalah bahwa pengalihan ganda dilakukandup2(10, 1);
sebelum menutup fd 10 yang merupakan salinan aslistdout
, sebelum menjalankan perintah berikutnya (echo
).Itu terjadi seperti itu karena pengalihan luar sebenarnya overlay pengalihan batin. Itu sebabnya ia menyalin kembali
stdout
fd asli setelah selesai.sumber