Bash iki kabuk istemi yazmaya çalışıyor mu?


11

Eğitim amaçlı olarak bir terminale bağlı çalışan bir bash işleminin strace çıktısına bakıyorum.

Benim bash işlemimde PID 2883 var.

Yazarım

[OP@localhost ~]$ strace -e trace=openat,read,write,fork,vfork,clone,execve -p 2883 2> bash.strace

Bir terminale doğru. Daha sonra bash sürecime giriyorum ve aşağıdaki etkileşime sahibim:

[OP@localhost ~]$ ls

Çıktıya baktığımda görüyorum

strace: Process 2883 attached
read(0, "l", 1)                         = 1
write(2, "l", 1)                        = 1
read(0, "s", 1)                         = 1
write(2, "s", 1)                        = 1
read(0, "\r", 1)                        = 1
write(2, "\n", 1)                       = 1
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fec6b1d8e50) = 3917
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3917, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
write(1, "\33]0;OP@localhost:~\7", 23) = 23
write(2, "[OP@localhost ~]$ ", 22)  = 22
...

Son iki satırda kafam karıştı. Bash'ın iki kabuk istemi yazmaya çalıştığı anlaşılıyor mu? Burada neler oluyor?

Yanıtlar:


24

<ESC>]0;Dizisi (gösterildiği gibi \33]0;strace tarafından) uç pencere başlığını ayarlamak için çıkış dizisidir. BEL karakteri ( \7) ile sonlandırılır , böylece ilki writepencere başlığını ayarlar. İkincisi gerçek bilgi istemini yazdırır. Kaçış dizisinden ayrı bile olsa, tam olarak aynı olmadıklarını unutmayın. [..]Pencere başlığı olmadığında bilgi isteminin çevresi vardır .

İlk yazmanın stdout'a (fd 1, ilk argüman write()) ve ikincisinin stderr'ye gittiğini de görebiliriz . Bash istemi stderr'a yazdırır, böylece ilk yazma başka bir yerden gelir. PROMPT_COMMANDDebian'ın Bash için varsayılan başlangıç ​​komut dosyalarındaki gibi bir yerde olabilir . Orada böyle bir şey var:

case "$TERM" in
xterm*|rxvt*)
    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
    ;;
*)
    ;;
esac

PROMPT_COMMANDÇalışıyorsa xtermveya rxvto kaçış dizisini desteklemesi gerektiğini ayarlar .


Neden bash'ın bir anda bir satırda okumaktan ziyade bir şeyleri karakter karakter okuduğunu biliyor musunuz? Ayrıca, bash neden stdout'a "l" ve "s" yazar? Ben benzer bir strace yaparsanız cat, iki fark vardır: giriş satır satır okur ve girişini stdout'a geri yansıtırken, girişi iki kez görüyorum (yazdığımda bir kez ve kedi onu tekrarladığında bir kez).
extremeaxe5

@ extremeaxe5, temelde Bash (veya daha doğrusu readline kütüphanesi), terminal tarafından yapılan oldukça sınırlı işleme dayanmak yerine, tüm komut satırı işlemeyi kendisi gerçekleştirir. Bir TAB karakteri veya ^A(Ctrl-A) veya çeşitli özel karakterler basıldığında ne yapılacağına karar vermek için hemen girişi almalıdır. Ayrıca, terminalin yankısını kapatır, böylece her belirli giriş karakteri için ne çıkarılacağına karar verebilir (yine, TAB genellikle bir TAB catçıkarmaz .) Bunların hiçbirini yapmaz. Bunu yaparsanız, dashherhangi bir komut satırı işlemesi yapmayan çalıştırmayı deneyin .
ilkkachu

Aslında, Bash'in read()bir seferde sadece bir bayt okuma çağrısının nedeni bir satırsonu satırını okuyamamasıdır. Yeni satır, aynı girişten de okunabilen harici bir program çalıştırmasına neden olabilir. (Ve bu program, yeni satırdan sonra herhangi bir karakteri okuyabilmelidir.) Eğer bunu önemsemek zorunda değilse, read()daha büyük bir sınırla çağırabilir ve ham modda terminal ile, genellikle girişi alır her seferinde bir karakter. (Giriş karakterlerinin ne kadar hızlı geleceğine ve sürecin nasıl planlandığına bağlı olacaktır.)
ilkkachu

İkinci yorumunuz sadece doğru görünüyor çünkü Bash komut satırı işlemeyi kendisi yapıyor.
extremeaxe5

@ extremeaxe5, evet, evet, herhalde ortak bir durum olduğu için bunu varsayıyordum. Ancak, kabuk terminalin satır düzenlemesine bağlı olsa bile, zamanlama hala bir sorun olabilir. İki satır hızlı bir şekilde arka arkaya gönderildiyse (veri yapıştırma işlemini düşünün) ve sistem kabuğun hemen planlanmaması (veya daha kötüsü, kabuk durdurulması) için yeterince yüklendiyse, daha read()büyük bir arabellek içeren her iki satır da aynı çağrı. Bir garantisi yoktur sanmıyorum read()ediyorum hep pişmiş modunda sadece bir satır döndürür.
ilkkachu
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.