Anda sudah mendapatkan beberapa jawaban yang sangat bagus. Biar saya tekankan bahwa ada dua konsep berbeda yang terlibat di sini, pemahamannya sangat membantu:
Latar Belakang: Deskriptor file vs. tabel file
Deskriptor file Anda hanya angka 0 ... n, yang merupakan indeks dalam tabel deskriptor file dalam proses Anda. Dengan konvensi, STDIN = 0, STDOUT = 1, STDERR = 2 (perhatikan bahwa istilah STDIN
dll. Di sini hanya simbol / makro yang digunakan oleh konvensi dalam beberapa bahasa pemrograman dan halaman manual, tidak ada "objek" sebenarnya yang disebut STDIN; untuk tujuan diskusi ini, STDIN adalah 0, dll.).
Tabel deskriptor file itu sendiri tidak mengandung informasi apa pun tentang file sebenarnya. Sebaliknya, ini berisi pointer ke tabel file yang berbeda; yang terakhir berisi informasi tentang file fisik aktual (atau perangkat blok, atau pipa, atau apa pun yang dapat ditangani oleh Linux melalui mekanisme file) dan informasi lebih lanjut (yaitu, apakah itu untuk membaca atau menulis).
Jadi, ketika Anda menggunakan >
atau <
di shell Anda, Anda cukup mengganti pointer dari masing-masing file descriptor untuk menunjuk ke hal lain. Sintaks 2>&1
hanya menunjuk deskriptor 2 ke manapun 1 poin. > file.txt
cukup terbuka file.txt
untuk menulis dan membiarkan STDOUT (file decsriptor 1) menunjukkan itu.
Ada barang lain, misalnya 2>(xxx)
(yaitu: membuat proses baru berjalan xxx
, membuat pipa, menghubungkan file descriptor 0 dari proses baru ke ujung pembacaan pipa dan menghubungkan file deskriptor 2 dari proses asli ke akhir penulisan pipa).
Ini juga merupakan dasar untuk "file handle magic" pada perangkat lunak selain shell Anda. Misalnya, Anda bisa, dalam skrip Perl Anda, dup
melisensikan deskriptor file STDOUT menjadi yang lain (sementara), lalu membuka kembali STDOUT ke file sementara yang baru dibuat. Mulai saat ini, semua output STDOUT dari skrip Perl Anda sendiri dan semua system()
panggilan skrip itu akan berakhir di file sementara itu. Setelah selesai, Anda dapat dup
mengirim kembali STDOUT Anda ke deskriptor sementara tempat Anda menyimpannya, dan presto, semuanya seperti sebelumnya. Anda bahkan dapat menulis ke deskriptor sementara itu, jadi sementara output STDOUT Anda yang sebenarnya pergi ke file sementara, Anda masih dapat benar-benar menampilkan barang-barang ke STDOUT nyata (umumnya, pengguna).
Menjawab
Untuk menerapkan informasi latar belakang yang diberikan di atas untuk pertanyaan Anda:
Dalam urutan apa shell menjalankan perintah dan mengalirkan redirection?
Kiri ke kanan.
<command> > file.txt 2>&1
fork
dari proses baru.
- Buka
file.txt
dan simpan penunjuknya di file descriptor 1 (STDOUT).
- Arahkan STDERR (file descriptor 2) ke apa pun yang ditunjukkan 1 fd sekarang (yang lagi-lagi sudah dibuka
file.txt
tentu saja).
exec
itu <command>
Ini rupanya mengarahkan stderr ke stdout terlebih dahulu, dan kemudian stdout yang dihasilkan diarahkan ke file.txt.
Ini masuk akal jika hanya ada satu meja, tetapi seperti yang dijelaskan di atas ada dua. File deskriptor tidak menunjuk satu sama lain secara rekursif, tidak masuk akal untuk berpikir "redirect STDERR ke STDOUT". Pikiran yang benar adalah "arahkan STDERR ke mana pun STDOUT menunjuk". Jika Anda mengubah STDOUT nanti, STDERR tetap di tempatnya, itu tidak secara ajaib sejalan dengan perubahan lebih lanjut ke STDOUT.