Mengapa mengarahkan redirect ke 2> & 1 dan 1> & 2?

36

Saya telah menemukan beberapa perintah yang menggunakan 2>&1dan 1>&2, tetapi saya tidak bisa memahami tujuan menggunakannya dan kapan saya harus menggunakannya.

Apa yang aku mengerti

Saya tahu itu 1mewakili keluar standar dan 2mewakili kesalahan standar. Saya mengerti bahwa 2>&1menggabungkan output 2ke 1dan sebaliknya.

Apa yang tidak saya dapatkan

  1. Kapan saya harus menggunakannya?
  2. Apa tujuannya?
Kacang Kacang Tanah
sumber

Jawaban:

39

Terkadang Anda ingin mengarahkan stdout dan stderr ke lokasi yang sama, Ini saat >&digunakan - ini mengarahkan satu deskriptor file ke yang lain.


Misalnya, jika Anda ingin menulis kedua stdout dan stderr ke file yang sama (baik itu /dev/nullatau output.txt), Anda dapat mengarahkan mereka secara terpisah, dengan

app 1>/dev/null 2>/dev/null

atau Anda bisa mengarahkan satu deskriptor file ke file, dan deskriptor file lainnya ke yang pertama:

app 1>/dev/null 2>&1

app 2>/dev/null 1>&2

Dalam contoh pertama, 2>&1arahkan file descriptor # 2 ke tempat # 1 sudah menunjuk. Contoh kedua mencapai hal yang sama, hanya mulai dengan stderr saja.

Sebagai contoh lain, ada beberapa kasus ketika stdout (deskriptor file # 1) sudah menunjuk ke lokasi yang diinginkan, tetapi Anda tidak dapat merujuknya dengan nama (mungkin terkait dengan pipa, soket, atau semacamnya). Ini sering terjadi ketika menggunakan ekspansi proses ( ` `atau $( )operator), yang biasanya hanya menangkap stdout, tetapi Anda mungkin ingin menyertakan stderr di dalamnya. Dalam hal ini, Anda juga akan menggunakan >&untuk mengarahkan stderr ke stdout:

out=$(app 2>&1)

Contoh umum lainnya adalah pager, atau grep, atau utilitas serupa, karena pipa |biasanya hanya bekerja di stdout, Anda akan mengarahkan stderr ke stdout sebelum menggunakan pipa:

app 2>&1 | grep hello

Bagaimana tahu mana 2>&1atau 1>&2benar? The sudah menyiapkan file descriptor pergi ke kanan >&, dan file descriptor Anda ingin redirect pergi ke kiri. ( 2>&1berarti "titik file descriptor # 2 ke file descriptor # 1".)


Beberapa shell memiliki jalan pintas untuk pengalihan umum; berikut adalah contoh dari Bash:

  • 1> dapat disingkat menjadi adil >

  • 1>foo 2>&1ke >&fooatau&>foo

  • 2>&1 | program untuk |& program

grawity
sumber
Saya tidak tahu bahwa melakukan app 1>/dev/null 2>&1berarti 2> & 1 akan menunjuk ke file yang sudah saya alihkan. Saya mengambilnya, saya bisa dengan mudah melakukannya app > /dev/null &>?
PeanutsMonkey
Saya mengalami kesulitan memahami the already set up fd goes to the right of >&, and the fd you want to redirect goes to the left. Apa yang Anda maksud dengan deskriptor file yang sudah diatur? Apa artinya itu hak?
PeanutsMonkey
Maaf, kecuali jika Anda bermaksud mengajari saya petunjuk, saya tidak mengikuti pernyataan yang Anda buat seperti yang disebutkan sebelumnya.
PeanutsMonkey
1
Ambil setiap deskriptor file redirect satu per satu, dari kiri ke kanan, dan terapkan aturan-aturan itu dalam urutan itu. Jika Anda pertama mengarahkan stdout ke file, maka arahkan stderr ke tempat yang ditunjuk oleh stdout kami, kemudian stderr dan stdout akan menuju ke file yang sama. Jika Anda menukar kedua pengalihan tersebut, maka Anda akan mendapatkan hasil yang berbeda (mengarahkan ulang stderr ke tempat stdout sekarang , kemudian memindahkan stdout untuk menunjuk ke file lain, sementara stderr melanjutkan ke tempat yang ditunjuk).
Jason
2

Satu situasi ketika Anda membutuhkannya adalah ketika Anda ingin menampilkan straceoutput dalam pager. stracemencetak outputnya ke standard error dan pipa umumnya menghubungkan output standar ke input standar, jadi Anda harus menggunakan redirect:

strace -p $pid 2>&1 | less
jpalecek
sumber
Apa maksudmu pipes generally connect standard output to standard input?
PeanutsMonkey
2
Maksud saya pipe ( |) mengambil output standar dari perintah pertama dan menghubungkannya ke input standar dari perintah kedua.
jpalecek
2

Terkadang Anda ingin mengalihkan keduanya stdout( 1) dan stderr( 2) ke lokasi yang sama ( /dev/null, misalnya). Salah satu cara untuk mencapai ini adalah:

$ program 1>/dev/null 2>/dev/null

Tapi kebanyakan orang mempersingkat ini dengan mengarahkan stderrke stdoutdengan 2>&1:

$ program 1>/dev/null 2>&1

Versi yang lebih pendek adalah:

$ program >&- 2>&-
Zaz
sumber
1

2: Ini untuk ketika Anda akan memiliki output yang berasal dari standard error dan standard out, dan Anda ingin mereka dikomposisi menjadi satu string.

1: Ketika Anda ingin memanipulasi output dari standard error dan standard out.

soando
sumber
Apa yang Anda maksud dengan memanipulasi? Pemahaman saya adalah bahwa apa pun yang dialihkan ke >2dikirim ke / dev / null. Atau apakah saya salah sepenuhnya?
PeanutsMonkey
Itu tidak benar. Dengan memanipulasi maksud saya pipa itu untuk grep atau yang serupa. Lihat di sini untuk contoh.
soandos
0

Saya menggunakannya untuk memulai pekerjaan terpisah:

someProgram 2>&1 >& my.log &

maka saya bisa keluar, dan beberapa program akan tetap berjalan. Fungsionalitas disediakan oleh Layar GNU, tmux dan beberapa program lainnya - tetapi di sini ia dicapai tanpa ketergantungan eksternal.

Adobe
sumber
1
Itu hanya berfungsi selama tidak ada SIGHUP yang dikirim ke program. Penggunaan yang lebih baik nohupatau disowndalam kasus seperti itu.
slhck
@ Slhck: ok. Tetapi jika saya woudn't mengirim SIGHUP ke program - tidak ada yang mau, kan?
Adobe
Tidak, terminal pengendali akan memperingatkan proses keluar dengan SIGHUP. Dalam praktiknya, jika Anda menjalankan shell jarak jauh melalui SSH dan keluar, proses Anda akan mati juga, misalnya.
slhck
@ Slhck: Tidak mungkin benar: Saya menggunakannya selama beberapa tahun - Saya keluar dari ssh, dan prosesnya masih berjalan.
Adobe
Saya harus melihat ini secara lebih rinci, tetapi hanya menempatkan program di latar belakang tidak bekerja untuk saya dalam semua kasus, dan itu pasti bahkan tidak bekerja pada mesin lokal saya. Zsh dan Bash berperilaku berbeda di sini juga, tampaknya.
slhck
0

Bayangkan ada direktori bernama tryyang memiliki tiga file ini:file file1 and file2.

Sekarang jalankan perintah ini:

cat file file1 file2 file3

Tiga file pertama terbuka tetapi catmelempar kesalahan saat membuka yang keempat karena tidak ada.

Sekarang jalankan:

cat file file1 file2 file3 1>outfile 2>&1

Anda tidak akan melihat output apa pun di layar: Pertama 1>outfileakan mengarahkan output dari perintah ke outfiledan kemudian akan mengarahkan ulang ( 2>&1) kesalahan yang dilemparkan saat mencoba membuka file3keoutfile .

1>&2 bekerja dengan cara yang sama dan mengarahkan aliran kesalahan ke output standar.

Semoga ini membantu!

Faiz
sumber
0

Skenario alternatif: perintah terminal menunjukkan output ke terminal lain

Gunakan ttyperintah di setiap terminal untuk mengidentifikasi mereka:

$ tty
/dev/pts/0

$ tty
/dev/pts/1

Dengan asumsi TTY ini, untuk mengarahkan stdout pertama ke yang kedua, jalankan ini di terminal pertama:

exec 1>/dev/pts/1

Catatan: Sekarang setiap output perintah akan ditampilkan di pts / 1

Untuk mengembalikan stdout perilaku default dari Poin / 0:

exec 1>/dev/pts/0

Lihat video ini untuk demonstrasi.

Vitalie Ghelbert
sumber
0

Kasus ketika mengarahkan kembali stderr ke stdout sudah dibahas di sini (misalnya menggunakannya untuk memfilter (grep) pesan kesalahan).

Kasus lainnya adalah mengarahkan stdout ke stderr. Usecase umum (setidaknya bagi saya) adalah mengirim peringatan / pesan kesalahan yang dicetak dengan "echo" (dalam skrip shell saya) ke stderr (sehingga mereka dapat menarik perhatian pengguna dengan lebih mudah).

Sebagai contoh,

echo "file \"${file\" does not exist..." 1>&2
umläute
sumber