GNU/Linux >> Belajar Linux >  >> Linux

gema atau cetak /dev/stdin /dev/stdout /dev/stderr

stdin , stdout , dan stderr adalah aliran dilampirkan ke masing-masing deskriptor file 0, 1, dan 2 dari suatu proses.

Pada prompt shell interaktif di terminal atau emulator terminal, ketiga deskriptor file tersebut akan merujuk ke deskripsi file terbuka yang sama yang akan diperoleh dengan membuka file perangkat terminal atau pseudo-terminal (sesuatu seperti /dev/pts/0 ) dalam mode baca+tulis.

Jika dari shell interaktif tersebut, Anda memulai skrip tanpa menggunakan pengalihan apa pun, skrip Anda akan mewarisi deskriptor file tersebut.

Di Linux, /dev/stdin , /dev/stdout , /dev/stderr adalah tautan simbolik ke /proc/self/fd/0 , /proc/self/fd/1 , /proc/self/fd/2 masing-masing, symlink khusus itu sendiri ke file aktual yang dibuka pada deskriptor file tersebut.

Mereka bukan stdin, stdout, stderr, mereka adalah file khusus yang mengidentifikasi file apa yang akan digunakan stdin, stdout, stderr (perhatikan bahwa ini berbeda di sistem lain selain Linux yang memiliki file khusus tersebut).

membaca sesuatu dari stdin berarti membaca dari deskriptor file 0 (yang akan menunjuk ke suatu tempat di dalam file yang direferensikan oleh /dev/stdin ).

Tapi di $(</dev/stdin) , shell tidak membaca dari stdin, ia membuka deskriptor file baru untuk membaca di file yang sama dengan yang dibuka di stdin (jadi membaca dari awal file, bukan ke tempat stdin saat ini).

Kecuali dalam kasus khusus perangkat terminal terbuka dalam mode baca+tulis, stdout dan stderr biasanya tidak terbuka untuk dibaca. Itu dimaksudkan untuk menjadi aliran yang Anda tulisi . Jadi membaca dari deskriptor file 1 umumnya tidak akan berfungsi. Di Linux, membuka /dev/stdout atau /dev/stderr untuk membaca (seperti pada $(</dev/stdout) ) akan berfungsi dan akan membiarkan Anda membaca dari file tempat stdout pergi (dan jika stdout adalah sebuah pipa, itu akan membaca dari ujung pipa yang lain, dan jika itu adalah soket, itu akan gagal karena Anda tidak bisa buka soket).

Dalam kasus skrip kami dijalankan tanpa pengalihan pada prompt shell interaktif di terminal, semua /dev/stdin, /dev/stdout dan /dev/stderr akan menjadi file perangkat terminal /dev/pts/x itu.

Membaca dari file-file khusus itu mengembalikan apa yang dikirim oleh terminal (apa yang Anda ketik di keyboard). Menulis kepada mereka akan mengirim teks ke terminal (untuk ditampilkan).

echo $(</dev/stdin)
echo $(</dev/stderr)

akan tetap sama. Untuk memperluas $(</dev/stdin) , shell akan membuka /dev/pts/0 itu dan membaca apa yang Anda ketik sampai Anda menekan ^D pada baris kosong. Mereka kemudian akan meneruskan perluasan (apa yang Anda ketikkan dihapus dari baris baru yang tertinggal dan tunduk pada split+glob) ke echo yang kemudian akan menampilkannya di stdout (untuk ditampilkan).

Namun di:

echo $(</dev/stdout)

di bash (dan bash saja), penting untuk disadari bahwa di dalam $(...) , stdout telah dialihkan. Sekarang menjadi pipa. Dalam kasus bash , proses shell anak sedang membaca konten file (di sini /dev/stdout ) dan menuliskannya ke dalam pipa, sedangkan induk membaca dari ujung yang lain untuk membentuk perluasan.

Dalam hal ini ketika proses bash anak itu membuka /dev/stdout , itu sebenarnya membuka ujung pembacaan pipa. Tidak ada yang akan datang dari itu, ini adalah situasi kebuntuan.

Jika Anda ingin membaca dari file yang ditunjuk oleh skrip stdout, Anda dapat mengatasinya dengan:

 { echo content of file on stdout: "$(</dev/fd/3)"; } 3<&1

Itu akan menduplikasi fd 1 ke fd 3, jadi /dev/fd/3 akan menunjuk ke file yang sama dengan /dev/stdout.

Dengan skrip seperti:

#! /bin/bash -
printf 'content of file on stdin: %s\n' "$(</dev/stdin)"
{ printf 'content of file on stdout: %s\n' "$(</dev/fd/3)"; } 3<&1
printf 'content of file on stderr: %s\n' "$(</dev/stderr)"

Saat dijalankan sebagai:

echo bar > err
echo foo | myscript > out 2>> err

Anda akan melihat di out setelah itu:

content of file on stdin: foo
content of file on stdout: content of file on stdin: foo
content of file on stderr: bar

Jika dibandingkan dengan membaca dari /dev/stdin , /dev/stdout , /dev/stderr , Anda ingin membaca dari stdin, stdout dan stderr (yang akan membuat lebih tidak masuk akal), Anda akan melakukannya:

#! /bin/sh -
printf 'what I read from stdin: %s\n' "$(cat)"
{ printf 'what I read from stdout: %s\n' "$(cat <&3)"; } 3<&1
printf 'what I read from stderr: %s\n' "$(cat <&2)"

Jika Anda memulai skrip kedua itu lagi sebagai:

echo bar > err
echo foo | myscript > out 2>> err

Anda akan melihat di out :

what I read from stdin: foo
what I read from stdout:
what I read from stderr:

dan di err :

bar
cat: -: Bad file descriptor
cat: -: Bad file descriptor

Untuk stdout dan stderr, cat gagal karena deskriptor file terbuka untuk menulis hanya, tidak membaca, perluasan $(cat <&3) dan $(cat <&2) kosong.

Jika Anda menyebutnya sebagai:

echo out > out
echo err > err
echo foo | myscript 1<> out 2<> err

(di mana <> terbuka dalam mode baca+tulis tanpa pemotongan), Anda akan melihat di out :

what I read from stdin: foo
what I read from stdout:
what I read from stderr: err

dan di err :

err

Anda akan melihat bahwa tidak ada yang dibaca dari stdout, karena printf sebelumnya telah menimpa konten out dengan what I read from stdin: foo\n dan meninggalkan posisi stdout di dalam file itu setelahnya. Jika Anda telah mempersiapkan out dengan beberapa teks yang lebih besar, seperti:

echo 'This is longer than "what I read from stdin": foo' > out

Kemudian Anda akan masuk ke out :

what I read from stdin: foo
read from stdin": foo
what I read from stdout: read from stdin": foo
what I read from stderr: err

Lihat bagaimana $(cat <&3) telah membaca apa yang tersisa setelah printf pertama dan melakukan itu juga memindahkan posisi stdout melewatinya sehingga printf berikutnya menampilkan apa yang dibaca setelahnya.


stdout dan stderr adalah keluaran, Anda tidak membaca darinya, Anda hanya dapat menulisnya. Misalnya:

echo "this is stdout" >/dev/stdout
echo "this is stderr" >/dev/stderr

program menulis ke stdout secara default sehingga yang pertama setara dengan

echo "this is stdout"

dan Anda dapat mengarahkan ulang stderr dengan cara lain seperti

echo "this is stderr" 1>&2

Linux
  1. Bagaimana Linux Menangani Beberapa Pemisah Jalur Berturut-turut (/home////username///file)?

  2. Seberapa Portabel /dev/stdin, /dev/stdout Dan /dev/stderr?

  3. Bagaimana cara menyandikan base64 /dev/random atau /dev/urandom?

  1. Bagaimana Anda menukar/dev/sda dengan/dev/sdb?

  2. Kapan saya harus menggunakan /dev/shm/ dan kapan saya harus menggunakan /tmp/?

  3. kernel:menonaktifkan /dev/kmem dan /dev/mem

  1. Bagaimana Linux menggunakan /dev/tty dan /dev/tty0

  2. Apakah salah menautkan /dev/random ke /dev/urandom di Linux?

  3. Perbedaan antara /dev/sda dan /dev/sda1