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 stdin
veya stdout
bir 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 stderr
değ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 cmd
stderr boruya gider, ama fd 1 kapalıdır. Herhangi cmd
bir çıktı yazmaya çalışırsa, bu bir EBADF
hata ile döner , eğer bir dosyayı açarsa, ilk serbest fd'yi alır ve stdout
komut buna karşı koruma sağlamadığı sürece açık dosyaya atanır ! İstediğimiz de değil.
Stdout'un cmd
yalnı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, cmd
1, 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ü cmd
onu 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, cmd
arka 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 bash
ile 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
>&3
yerine 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-command
veya any-builtin
döndü. Sorunu çözmek için bir düzeltme eki (2013-02-19) kullanıma sunulmuştur.