3>&4-bash tarafından da desteklenen bir ksh93 uzantısıdır ve bu kısadır 3>&4 4>&-, yani 3 şimdi 4'ün kullanıldığı ve 4'ün kapalı olduğu noktayı gösterir, bu yüzden 4 ile işaretlenen şimdi 3'e taşınmıştır.
Tipik kullanım, aşağıdaki gibi çoğalttığınız stdinveya stdoutbir kopyasını kaydettiğiniz ve geri yüklemek istediğiniz durumlarda olabilir:
Bir değişkenin stdout'unu yalnız bırakırken bir komutun stderr'ını (ve yalnızca stderr) yakalamak istediğinizi varsayalım.
Komut ikamesi var=$(cmd), bir boru oluşturur. Borunun yazma ucu cmd'stdout (dosya tanımlayıcı 1) olur ve diğer uç değişkeni doldurmak için kabuk tarafından okunur.
İstersen Şimdi stderrdeğişkene gitmek, bunu yapabilirsiniz: var=$(cmd 2>&1). Şimdi hem fd 1 (stdout) hem de 2 (stderr) boruya (ve sonunda değişkene) gider, bu da istediğimiz şeyin sadece yarısıdır.
Eğer yaparsak var=$(cmd 2>&1-)(kısa var=$(cmd 2>&1 >&-), şimdi sadece cmdstderr boruya gider, ama fd 1 kapalıdır. Herhangi cmdbir çıktı yazmaya çalışırsa, bu bir EBADFhata ile döner , eğer bir dosyayı açarsa, ilk serbest fd'yi alır ve stdoutkomut buna karşı koruma sağlamadığı sürece açık dosyaya atanır ! İstediğimiz de değil.
Stdout'un cmdyalnız bırakılmasını istiyorsak, komut ikamesinin dışında işaret ettiği kaynağa işaret etmek istiyorsak, o kaynağı komut ikamesinin içine getirmek için bir şekilde ihtiyacımız var. Bunun için komut değiştirme yerine stdout dışında bir kopyasını içine alabiliriz.
{
var=$(cmd)
} 3>&1
Hangi yazmak için temiz bir yoldur:
exec 3>&1
var=$(cmd)
exec 3>&-
(aynı zamanda sonunda kapatmak yerine fd 3'ü geri yükleme avantajına sahiptir).
Daha sonra {(veya exec 3>&1) üzerine ve }her ikisi de fd 1 ve 3 başlangıçta işaret ettiği aynı fd 1 kaynağına işaret eder. fd 3 ayrıca komut ikamesi içindeki kaynağı işaret edecektir (komut ikamesi sadece fd 1, stdout'u yönlendirir). Yukarıda, cmd1, 2, 3 numaralı diskler için var:
- boru var
- dokunulmamış
- Komut yerine koymanın dışında 1 puanla aynı
Bunu şu şekilde değiştirirsek:
{
var=$(cmd 2>&1 >&3)
} 3>&1-
Sonra olur:
- Komut yerine koymanın dışında 1 puanla aynı
- boru var
- Komut yerine koymanın dışında 1 puanla aynı
Şimdi, istediğimizi aldık: stderr boruya gidiyor ve stdout dokunulmadan bırakılıyor. Ancak, bu fd 3'ü sızdırıyoruz cmd.
Komutlar (kural gereği) 0 - 2 arasındaki fd'lerin açık olduğunu ve standart girdi, çıktı ve hata olduğunu varsayarken, diğer fd'lerden hiçbir şey kabul etmezler. Büyük olasılıkla bu fd 3'ü el değmeden bırakacaklar. Başka bir dosya tanımlayıcıya ihtiyaç duyarlarsa, yalnızca open()/dup()/socket()...ilk kullanılabilir dosya tanımlayıcısını döndürecek bir dosya yaparlar . Eğer (bunu yapan bir kabuk betiği gibi exec 3>&1) fdözel olarak kullanmaları gerekiyorsa , önce bir şeye atayacaklar (ve bu süreçte, fd 3'ümüz tarafından tutulan kaynak bu süreç tarafından serbest bırakılacak).
Fd 3'ü kapatmak iyi bir uygulamadır, çünkü cmdonu kullanmaz, ancak aramadan önce onu atanmış olarak bırakmak önemli değildir cmd. Sorunlar şunlar olabilir: cmd(ve potansiyel olarak ortaya çıkardığı diğer süreçler) bir tane daha az kullanılabilir. Potansiyel olarak daha ciddi bir problem, fd'nin işaret ettiği kaynağın, cmdarka planda ortaya çıkan bir süreç tarafından tutulabilmesidir . Bu kaynağın bir boru veya başka bir süreçler arası iletişim kanalı (betiğinizin çalıştırıldığı gibi script_output=$(your-script)) olması endişe verici olabilir , çünkü diğer uçtan okuma işlemi dosya sonuna kadar asla dosya sonu görmeyecektir arkaplan işlemi sona erer.
Yani burada yazmak daha iyi:
{
var=$(cmd 2>&1 >&3 3>&-)
} 3>&1
Hangi ile bashile kısaltılabilir:
{
var=$(cmd 2>&1 >&3-)
} 3>&1
Nadiren kullanılma nedenlerini özetlemek için:
- standart olmayan ve sadece sözdizimsel şekerdir. Birkaç tuş vuruşunu kaydetmeyi, betiğinizi bu sıra dışı özelliğe alışkın olmayan kişiler için daha az taşınabilir ve daha az belirgin hale getirerek dengelemeniz gerekir.
- Orijinal fd'yi çoğalttıktan sonra kapatma ihtiyacı genellikle göz ardı edilir, çünkü çoğu zaman sonuçtan muzdarip değiliz, bu yüzden veya
>&3yerine yaparız .>&3->&3 3>&-
Nadiren kullanıldığının kanıtı, bildiğiniz gibi bash'da sahte olduğu . Bash compound-command 3>&4-veya any-builtin 3>&4-yapraklar fd 4 sonra bile kapalı compound-commandveya any-builtindöndü. Sorunu çözmek için bir düzeltme eki (2013-02-19) kullanıma sunulmuştur.