TL; DR
Kullanmayın -t
. -t
Uzak ana bilgisayarda bir sözde terminal içerir ve yalnızca görsel uygulamaları bir terminalden çalıştırmak için kullanılmalıdır.
açıklama
Satır besleme karakteri (aynı zamanda newline olarak da bilinir \n
) veya terminale gönderildiğinde terminale imlecini aşağı doğru hareket ettirmesini söyleyen karakterdir.
Yine de, seq 3
bir terminalde koşarken , seq
şöyle bir 1\n2\n3\n
şeye yazdığı yer /dev/pts/0
:
1
2
3
fakat
1
2
3
Neden?
Aslında seq 3
(veya ssh host seq 3
bu konuda) yazdığında 1\n2\n3\n
, terminal görür 1\r\n2\r\n3\r\n
. Yani, satır akışları satırbaşına (ki bu sırada terminaller imlecini ekranın soluna taşır) ve satır akışına çevrilmiştir.
Bu terminal aygıt sürücüsü tarafından yapılır. Daha doğrusu, terminalde (veya sözde terminal) cihazın hat disiplini, çekirdeğin içinde bulunan bir yazılım modülüdür.
Bu çizgi disiplininin davranışını stty
komutla kontrol edebilirsiniz . LF
-> çevirisi ile CRLF
açıldı
stty onlcr
(genellikle varsayılan olarak etkindir). Şununla kapatabilirsiniz:
stty -onlcr
Veya tüm çıktı işlemlerini şu yöntemlerle kapatabilirsiniz:
stty -opost
Bunu yapar ve koşarsanız seq 3
, göreceksiniz:
$ stty -onlcr; seq 3
1
2
3
beklenildiği gibi.
Şimdi, ne zaman:
seq 3 > some-file
seq
artık bir terminale yazmıyor, bir dosyaya yazıyor, çeviri yapılmadı. Yani some-file
içermiyor 1\n2\n3\n
. Çeviri sadece bir terminal cihaza yazarken yapılır. Ve sadece gösterim için yapıldı.
Benzer şekilde, ne zaman:
ssh host seq 3
ssh
1\n2\n3\n
ne ssh
çıktısı olursa olsun ne yazıyor .
Aslında olan, seq 3
komutun host
stdout ile bir boruya yönlendirilmiş olarak çalıştırılmasıdır . Ana ssh
bilgisayardaki sunucu borunun diğer ucunu okur ve şifreli kanal üzerinden ssh
istemcinize gönderir ve ssh
müşteri bu durumda stdout'una yazar, bu durumda, ekrana LF
çevrildiği sahte terminal bir cihaz CRLF
.
Birçok etkileşimli uygulama, stdout'ları bir terminal olmadığında farklı davranır. Örneğin, eğer çalıştırırsanız:
ssh host vi
vi
beğenmedi, çıktısının bir boruya gitmesini sevmiyor. Örneğin imleç konumlandırma kaçış dizilerini anlayabilen bir cihazla konuşmadığını düşünüyor.
Yani ssh
bunun için bir -t
seçenek var. Bu seçenekle, ana bilgisayardaki ssh sunucusu sahte terminal cihazı oluşturur ve bunun stdout (ve stdin ve stderr) olmasını sağlar vi
. Ne vi
o, terminal cihazının yazdığı uzak uçbirimsi hat disiplin geçer ve tarafından okunur ssh
sunucu ve şifreli kanal üzerinden gönderilen ssh
istemci. Daha önce olduğu gibi aynı, bir boru kullanmak yerine , ssh
sunucunun sahte terminal kullanması dışında .
Diğer fark, müşteri tarafında, ssh
istemcinin terminali raw
moda ayarlamasıdır. Bu orada çeviri yapılmadığı anlamına gelir ( opost
devre dışı bırakılmış ve ayrıca giriş tarafı davranışları). Örneğin, yazarken Ctrl-C, kesmek yerine ssh
, bu ^C
karakter uzak tarafa gönderilir, burada uzak sözde terminalin çizgi disiplini, kesmeyi uzak komutuna gönderir .
Ne zaman yaparsın:
ssh -t host seq 3
seq 3
1\n2\n3\n
Bir sözde terminal aygıtı olan stdout'una yazar . Yüzünden onlcr
tercüme olduğunu, ana bilgisayarda için 1\r\n2\r\n3\r\n
ve şifreli kanal üzerinden size gönderilen. Kendi tarafında çeviri ( onlcr
devre dışı) yoktur, bu yüzden 1\r\n2\r\n3\r\n
dokunulmaz ( raw
mod nedeniyle ) ve terminal emülatörünüzün ekranında doğru şekilde görüntülenir.
Şimdi, eğer yaparsan:
ssh -t host seq 3 > some-file
Yukarıdan fark yok. ssh
aynı şeyi yazacak:, 1\r\n2\r\n3\r\n
ama bu sefer içine some-file
.
Yani temelde LF
, çıktısının tümü girdi seq
diline CRLF
çevrildi some-file
.
Bunu yaparsanız aynı:
ssh -t host cat remote-file > local-file
Tüm LF
karakterler (0x0a bayt) CRLF'ye (0x0d 0x0a) çevrilmiştir.
Muhtemelen dosyanızdaki bozulmanın nedeni budur. İkinci daha küçük dosya durumunda, dosya 0x0a bayt içermez, bu nedenle bozulma olmaz.
Farklı tty ayarlarıyla farklı yolsuzluk türleri alabileceğinizi unutmayın. Başka bir olası yolsuzluk türü -t
, eğer başlangıç dosyalarınız host
( ~/.bashrc
, ~/.ssh/rc
...) 'ın stderr'lerine bir şeyler yazıyorsa, çünkü -t
uzak kabuğun stdout ve stderr'leri stdout ile birleştirilir ssh
(ikisi de sözde olurlar) -terminal cihaz).
Uzaktan kumandanın cat
orada bir terminal cihazına çıkış yapmasını istemezsiniz .
İstediğiniz:
ssh host cat remote-file > local-file
Yapabilirsin:
ssh -t host 'stty -opost; cat remote-file` > local-file
İşe yarayacak ( yukarıda tartışılan stderr yolsuzluk vakası dışında ), ancak bu gereksiz sözde terminal-terminal katmanını çalıştıracağınız için bile alt-optimal olacaktır host
.
Biraz daha eğlenceli:
$ ssh localhost echo | od -tx1
0000000 0a
0000001
TAMAM.
$ ssh -t localhost echo | od -tx1
0000000 0d 0a
0000002
LF
çevrildi CRLF
$ ssh -t localhost 'stty -opost; echo' | od -tx1
0000000 0a
0000001
Tekrar tamam.
$ ssh -t localhost 'stty olcuc; echo x'
X
Bu, terminal hattı disiplini tarafından yapılabilecek bir çıktı son işleme biçimidir.
$ echo x | ssh -t localhost 'stty -opost; echo' | od -tx1
Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Inappropriate ioctl for device
0000000 0a
0000001
ssh
Sunucuya, kendi girişi bir terminal olmadığında sahte terminal kullanmasını reddetti. -tt
Bununla zorlayabilirsin :
$ echo x | ssh -tt localhost 'stty -opost; echo' | od -tx1
0000000 x \r \n \n
0000004
Çizgi disiplini giriş tarafında çok daha fazlasını yapar.
Burada, echo
girişini okumuyor veya çıktısı istenmiyor x\r\n\n
, peki bu nereden geliyor? Bu echo
, uzak sözde terminalin ( stty echo
) yerel adresidir . ssh
Sunucu besleyen x\n
uzak sözde-terminalinin ana yanına istemciden okuyun. Ve bunun çizgi disiplini onu geri yansıtıyor (daha önce stty opost
çalıştırma, bu yüzden görüyoruz CRLF
ve görmüyoruz LF
). Bu, uzak uygulamanın stdin'den bir şey okuyup okumamasından bağımsızdır.
$ (sleep 1; printf '\03') | ssh -tt localhost 'trap "echo ouch" INT; sleep 2'
^Couch
0x3
Karakter geri yankılandı ^C
( ^
ve C
) nedeniyle stty echoctl
kabuk ve uyku nedeniyle SIGINT al stty isig
.
Öyleyse:
ssh -t host cat remote-file > local-file
yeterince kötü ama
ssh -tt host 'cat > remote-file' < local-file
dosyaları diğer tarafa aktarmak için çok daha kötüdür. Tüm özel karakterleri ile> LF çeviri değil, aynı zamanda sorunları (- Bazı CR alırsınız ^C
, ^Z
, ^D
, ^?
, ^S
...) ve ayrıca uzaktan cat
sonu ne zaman eof görmez local-file
ulaşıldığında, sadece ^D
bir sonraki gönderilir \r
, \n
veya terminalinizde ^D
olduğu gibi başka cat > file
.
-t
transferini kırar seçeneği. Çok özel bir sebepten gerekmedikçe-t
veya kullanmayın-T
. Varsayılan durum çoğu durumda işe yarar, bu seçeneklere çok nadir ihtiyaç duyulur.