stdin
, stdout
Ve stderr
olan akımlar bağlı dosya tanımlayıcıları , 0, 1 ve 2, sırasıyla bir işlem.
Bir terminal veya terminal öykünücüsünde etkileşimli bir kabuk isteminde, tüm bu 3 dosya tanımlayıcısı , okuma + yazma işleminde bir terminal veya sözde terminal aygıt dosyası (benzeri bir şey ) açılarak elde edilen aynı açık dosya açıklamasına başvurur. /dev/pts/0
modu.
Bu etkileşimli kabuktan, komut dosyanızı herhangi bir yönlendirme kullanmadan başlatırsanız, komut dosyanız bu dosya tanımlayıcılarını devralır.
Linux'ta /dev/stdin
, /dev/stdout
, /dev/stderr
simgesel bağlardır /proc/self/fd/0
, /proc/self/fd/1
, /proc/self/fd/2
sırasıyla kendileri bu dosya göstericisi üzerinde açık olan gerçek dosyaya özel sembolik bağ.
Bunlar stdin, stdout, stderr değil, stdin, stdout, stderr'ın hangi dosyalara gittiğini tanımlayan özel dosyalardır (Linux'un bu özel dosyaları olan diğer sistemlerde farklı olduğunu unutmayın).
stdin'den bir şey okumak, dosya tanımlayıcı 0'dan (başvurulan dosyanın içinde bir yere işaret edecek) okumak anlamına gelir /dev/stdin
.
Ancak $(</dev/stdin)
, kabuk stdin'den okuma yapmıyor, stdin'de açık olanla aynı dosyayı okumak için yeni bir dosya tanımlayıcısı açar (bu nedenle stdin'in şu anda işaret ettiği yerde değil, dosyanın başından itibaren okumak).
Okuma + yazma modunda açık olan terminal cihazlarının özel durumu dışında, stdout ve stderr genellikle okumaya açık değildir. Onlar sizin yazdığınız akışlar içindir . Dolayısıyla, dosya tanımlayıcı 1'den okumak genellikle çalışmaz. Linux'ta, açmak /dev/stdout
veya /dev/stderr
okumak için (olduğu gibi $(</dev/stdout)
) işe yarar ve stdout'un gittiği dosyadan (ve stdout bir boru ise, borunun diğer ucundan okuyacak ve bir soket olup olmadığını) okumanıza izin verir. , bir soketi açamadığınız için başarısız olur ).
Bir terminalde etkileşimli bir kabuk isteminde yeniden yönlendirilmeden çalıştırılan komut dosyamızda, / dev / stdin, / dev / stdout ve / dev / stderr öğelerinin tümü / dev / pts / x terminal aygıt dosyası olacaktır.
Bu özel dosyalardan okumak, terminal tarafından gönderilenleri (klavyede yazdıklarınızı) döndürür. Onlara yazdığınızda metin terminale gönderilir (gösterim için).
echo $(</dev/stdin)
echo $(</dev/stderr)
aynı olacak. Genişletmek için $(</dev/stdin)
, kabuk bu / dev / pts / 0'ı açar ve ^D
boş bir satıra basana kadar yazdıklarınızı okur . Daha sonra genişletmeyi (son satırların soyulmuş ve bölünmüş + glob'a tabi olan yazdığınız) echo
daha sonra stdout'ta (görüntü için) çıktılayacaklardır.
Ancak:
echo $(</dev/stdout)
içinde bash
( ve bash
yalnızca ), söz konusu iç gerçekleştirmek için önemli $(...)
, stdout'u yönlendirildi. Şimdi bir boru. Alt bash
kabuk işlemi, dosyanın içeriğini (burada /dev/stdout
) okur ve boruya yazar, üst öğe genişlemeyi oluşturmak için diğer uçtan okur.
Bu durumda, bu çocuk bash işlemi açıldığında /dev/stdout
, aslında borunun okuma ucunu açar . Bundan hiçbir şey gelmeyecek, bu bir kilitlenme durumu.
Komut dosyaları stdout tarafından işaret edilen dosyadan okumak isterseniz, bununla birlikte çalışacaksınız:
{ echo content of file on stdout: "$(</dev/fd/3)"; } 3<&1
Bu, fd 1'i fd 3 üzerine çoğaltır, böylece / dev / fd / 3 / dev / stdout ile aynı dosyayı gösterir.
Gibi bir komut dosyası ile:
#! /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)"
Şu şekilde çalıştırıldığında:
echo bar > err
echo foo | myscript > out 2>> err
Daha out
sonra görecektiniz :
content of file on stdin: foo
content of file on stdout: content of file on stdin: foo
content of file on stderr: bar
Okuma aksine olursa /dev/stdin
, /dev/stdout
, /dev/stderr
, sen Stdin, stdout ve stderr (hatta daha az mantıklı olacaktır) okumak istedim, yapacağın:
#! /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)"
Bu ikinci betiği tekrar şu şekilde başlattıysanız:
echo bar > err
echo foo | myscript > out 2>> err
Şunu görürsünüz out
:
what I read from stdin: foo
what I read from stdout:
what I read from stderr:
ve içinde err
:
bar
cat: -: Bad file descriptor
cat: -: Bad file descriptor
Stdout ve stderr için cat
başarısız olur, çünkü dosya tanımlayıcıları okuma için değil, yalnızca yazma için açıktır , genişlemesi $(cat <&3)
ve $(cat <&2)
boştur.
Eğer şöyle çağırdıysanız:
echo out > out
echo err > err
echo foo | myscript 1<> out 2<> err
( <>
okuma + yazma modunda kesme olmadan açılır), şunu görürsünüz out
:
what I read from stdin: foo
what I read from stdout:
what I read from stderr: err
ve içinde err
:
err
Stdout'tan hiçbir şey okunmadığını fark edeceksiniz, çünkü önceki printf
, out
ile içeriğinin üzerine what I read from stdin: foo\n
yazmış ve bu dosyadaki stdout konumunu hemen sonra bırakmıştı. Daha out
büyük bir metinle hazırlanırsanız, örneğin:
echo 'This is longer than "what I read from stdin": foo' > out
Sonra içeri girersiniz 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
$(cat <&3)
İlkinden sonra kalanları nasıl okuduğunu printf
ve bunu yaparak stdout pozisyonunu nasıl geçtiğini görün, böylece bir sonraki printf
okunandan sonra çıktı alın.
echo x
aynı değildirecho x > /dev/stdout
stdout'u bir boru veya tty cihaz gibi bazı karakter cihazlara gitmezse. Örneğin, stdout normal bir dosyaya giderse dosyayıecho x > /dev/stdout
keser ve içeriğini geçerli stdout konumunax\n
yazmak yerine onunla değiştirirx\n
.