yankı veya baskı / dev / stdin / dev / stdout / dev / stderr


14

/ Dev / stdin, / dev / stdout ve / dev / stderr değerini yazdırmak istiyorum.

İşte benim basit senaryom:

#!/bin/bash
echo your stdin is : $(</dev/stdin)
echo your stdout is : $(</dev/stdout)
echo your stderr is : $(</dev/stderr)

aşağıdaki boruları kullanıyorum:

[root@localhost home]# ls | ./myscript.sh
[root@localhost home]# testerr | ./myscript.sh

sadece $(</dev/stdin)işe yarıyor gibi görünüyor, ben de bazı diğer sorular kullanan insanların kullandığı: "${1-/dev/stdin}"başarılı olmadan çalıştı.

Yanıtlar:


30

stdin, stdoutVe stderrolan 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/0modu.

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/stderrsimgesel bağlardır /proc/self/fd/0, /proc/self/fd/1, /proc/self/fd/2sı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/stdoutveya /dev/stderrokumak 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 ^Dboş 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) echodaha sonra stdout'ta (görüntü için) çıktılayacaklardır.

Ancak:

echo $(</dev/stdout)

içinde bash( ve bashyalnızca ), söz konusu iç gerçekleştirmek için önemli $(...), stdout'u yönlendirildi. Şimdi bir boru. Alt bashkabuk 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 outsonra 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 catbaş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, outile içeriğinin üzerine what I read from stdin: foo\nyazmış ve bu dosyadaki stdout konumunu hemen sonra bırakmıştı. Daha outbü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 printfokunandan sonra çıktı alın.


2

stdoutve stderrçıktılardır, onlardan okumazsınız, sadece onlara yazabilirsiniz. Örneğin:

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

programlar varsayılan olarak stdout'a yazar, böylece ilki eşdeğerdir

echo "this is stdout"

stderr'ı aşağıdaki gibi yönlendirebilirsiniz:

echo "this is stderr" 1>&2

1
Linux'ta, echo xaynı değildir echo x > /dev/stdoutstdout'u bir boru veya tty cihaz gibi bazı karakter cihazlara gitmezse. Örneğin, stdout normal bir dosyaya giderse dosyayı echo x > /dev/stdoutkeser ve içeriğini geçerli stdout konumuna x\nyazmak yerine onunla değiştirir x\n.
Stéphane Chazelas

@ Michael-Daffin> Teşekkürler, eğer stdout ve stderr okumak istersem sadece kedi kullanabilir miyim? (dosya oldukları için), örneğin kullanıcıya meydana gelen son hatayı göstermek istiyorum echo this is your error $(cat /dev/stderr)?
Omar BISTAMI

@OmarBISTAMI Sen okuyamıyorsun stdoutve stderronlar çıktılar.
Kusalananda

1

myscript.sh:

#!/bin/bash
filan -s

O zaman koş:

$ ./myscript.sh
    0 tty /dev/pts/1
    1 tty /dev/pts/1
    2 tty /dev/pts/1

$ ls | ./myscript.sh
    0 pipe 
    1 tty /dev/pts/1
    2 tty /dev/pts/1

$ ls | ./myscript.sh > out.txt
$ cat out.txt
    0 pipe 
    1 file /tmp/out.txt
    2 tty /dev/pts/1

Muhtemelen yüklemeniz gerekir filanile sudo apt install socatilk.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.