इस बाइनरी फ़ाइल को "ssh -t" में क्यों बदला जा रहा है?


29

मैं SSH से अधिक फ़ाइलों की प्रतिलिपि बनाने की कोशिश कर रहा हूं , लेकिन scpसटीक फ़ाइल नाम जो मुझे चाहिए, उसे नहीं जानने के कारण उपयोग नहीं कर सकता । हालाँकि छोटी बाइनरी फाइलें और टेक्स्ट फाइलें ठीक ट्रांसफर होती हैं, बड़ी बाइनरी फाइलें बदल जाती हैं। यहाँ सर्वर पर फ़ाइल है:

remote$ ls -la
-rw-rw-r--  1 user user 244970907 Aug 24 11:11 foo.gz
remote$ md5sum foo.gz 
9b5a44dad9d129bab52cbc6d806e7fda foo.gz

यहाँ फ़ाइल के बाद मैंने इसे स्थानांतरित कर दिया है:

local$ time ssh me@server.com -t 'cat /path/to/foo.gz' > latest.gz

real    1m52.098s
user    0m2.608s
sys     0m4.370s
local$ md5sum latest.gz
76fae9d6a4711bad1560092b539d034b  latest.gz

local$ ls -la
-rw-rw-r--  1 dotancohen dotancohen 245849912 Aug 24 18:26 latest.gz

ध्यान दें कि डाउनलोड की गई फ़ाइल सर्वर पर एक से बड़ी है! हालाँकि, यदि मैं एक बहुत ही छोटी फ़ाइल के साथ ऐसा करता हूं, तो सब कुछ अपेक्षित रूप से काम करता है:

remote$ echo "Hello" | gzip -c > hello.txt.gz
remote$ md5sum hello.txt.gz
08bf5080733d46a47d339520176b9211  hello.txt.gz

local$ time ssh me@server.com -t 'cat /path/to/hello.txt.gz' > hi.txt.gz

वास्तविक 0m3.041s उपयोगकर्ता 0m0.013s sys 0m0.005s

local$ md5sum hi.txt.gz
08bf5080733d46a47d339520176b9211  hi.txt.gz

इस मामले में दोनों फ़ाइल आकार 26 बाइट्स हैं।

छोटी फाइलें ठीक क्यों हस्तांतरित हो सकती हैं, लेकिन बड़ी फ़ाइलों को कुछ बाइट्स मिल जाती हैं?


10
यह -tविकल्प है, जो हस्तांतरण को तोड़ता है। उपयोग न करें -tया -T, जब तक कि आपको एक बहुत विशिष्ट कारण के लिए उनकी आवश्यकता न हो। अधिकांश मामलों में डिफ़ॉल्ट काम करता है, इसलिए उन विकल्पों की बहुत कम आवश्यकता होती है।
कैस्परल्ड

3
कभी नहीं सोचा था कि मैं इस सदी में यह कहूंगा, लेकिन यदि आप ssh -t catफ़ाइलों को स्थानांतरित करने का एकमात्र तरीका है तो आप uuencode और uudecode कोशिश कर सकते हैं ।
मार्क प्लॉटनिक

1
@MarkPlotnick uuencode / uudecode का आधुनिक संस्करण अब base64 / base64 -d
Archemar

जवाबों:


60

टी एल; डॉ

उपयोग न करें -t-tरिमोट होस्ट पर एक छद्म टर्मिनल शामिल है और इसका उपयोग केवल टर्मिनल से दृश्य अनुप्रयोगों को चलाने के लिए किया जाना चाहिए।

व्याख्या

लाइनफीड चरित्र (जिसे न्यूलाइन या के रूप में भी जाना जाता है \n) वह है जो टर्मिनल पर भेजे जाने पर टर्मिनल को अपने कर्सर को नीचे ले जाने के लिए कहता है।

फिर भी, जब आप seq 3एक टर्मिनल में दौड़ते हैं , तो वह कुछ ऐसा seqलिखता 1\n2\n3\nहै /dev/pts/0, जिसे आप नहीं देखते हैं:

1
 2
  3

परंतु

1
2
3

ऐसा क्यों है?

दरअसल, जब seq 3(या ssh host seq 3उस मामले के लिए) लिखते हैं 1\n2\n3\n, तो टर्मिनल देखता है 1\r\n2\r\n3\r\n। यही है, लाइन-फीड को कैरिज-रिटर्न (जिस पर टर्मिनल अपने कर्सर को स्क्रीन के बाईं ओर वापस ले जाते हैं) और लाइन-फीड में अनुवाद किया गया है।

यह टर्मिनल डिवाइस ड्राइवर द्वारा किया जाता है। अधिक सटीक रूप से, टर्मिनल (या छद्म टर्मिनल) डिवाइस के लाइन-डिस्क्रिप्शन द्वारा, एक सॉफ्टवेयर मॉड्यूल जो कर्नेल में रहता है।

आप sttyकमांड के साथ उस लाइन अनुशासन के व्यवहार को नियंत्रित कर सकते हैं । LF-> CRLFका अनुवाद चालू है

stty onlcr

(जो आमतौर पर डिफ़ॉल्ट रूप से सक्षम होता है)। आप इसे बंद कर सकते हैं:

stty -onlcr

या आप सभी आउटपुट प्रोसेसिंग को बंद कर सकते हैं:

stty -opost

यदि आप ऐसा करते हैं और चलाते हैं seq 3, तो आप देखेंगे:

$ stty -onlcr; seq 3
1
 2
  3

जैसा सोचा था।

अब, जब आप करते हैं:

seq 3 > some-file

seqअब टर्मिनल पर नहीं लिख रहा है, यह एक फ़ाइल में लिख रहा है, कोई अनुवाद नहीं हो रहा है। तो some-fileहोता है 1\n2\n3\n। अनुवाद केवल एक टर्मिनल डिवाइस पर लिखते समय किया जाता है। और यह केवल प्रदर्शन के लिए किया गया है।

इसी तरह, जब आप करते हैं:

ssh host seq 3

sshइस बात की 1\n2\n3\nपरवाह किए बिना कि sshआउटपुट किस ओर जाता है।

वास्तव में क्या होता है कि seq 3कमांड को hostउसके स्टडआउट से पाइप पर रीडायरेक्ट किया जाता है। sshमेजबान पर सर्वर पाइप के दूसरे छोर पढ़ता है और इस पर अपने को एन्क्रिप्टेड चैनल भेज sshग्राहक और sshग्राहक इसे अपनी stdout पर एक छद्म टर्मिनल डिवाइस है, जहां लिखते हैं, आपके मामले में LFरों में अनुवाद कर रहे हैं CRLFप्रदर्शन के लिए।

कई इंटरएक्टिव अनुप्रयोग अलग व्यवहार करते हैं जब उनका स्टडआउट टर्मिनल नहीं होता है। उदाहरण के लिए, यदि आप चलाते हैं:

ssh host vi

viयह पसंद नहीं है, यह अपने उत्पादन एक पाइप के लिए जा रहा पसंद नहीं है। यह सोचता है कि यह एक उपकरण से बात नहीं कर रहा है जो उदाहरण के लिए कर्सर पोजिशनिंग एस्केप सीक्वेंस को समझने में सक्षम है।

तो sshउसके लिए -tविकल्प है। उस विकल्प के साथ, होस्ट पर ssh सर्वर एक छद्म टर्मिनल डिवाइस बनाता है और बनाता है कि stdout (और stdin, और stderr) vi। क्या viहै कि टर्मिनल डिवाइस पर लिखते हैं कि दूरदराज के छद्म टर्मिनल लाइन अनुशासन के माध्यम से चला जाता है और द्वारा पढ़ा जाता है sshसर्वर और करने के लिए एन्क्रिप्टेड चैनल के द्वारा भेजा sshग्राहक। यह पहले की तरह ही है सिवाय इसके कि एक पाइप का उपयोग करने के बजाय , sshसर्वर एक छद्म टर्मिनल का उपयोग करता है ।

अन्य अंतर यह है कि क्लाइंट की तरफ, sshक्लाइंट टर्मिनल को rawमोड में सेट करता है। इसका मतलब है कि कोई अनुवाद वहां नहीं किया गया है ( opostअक्षम है और अन्य इनपुट-साइड व्यवहार भी है)। उदाहरण के लिए, जब आप टाइप करते हैं, तो Ctrl-Cव्यवधान डालने के बजाय ssh, उस ^Cवर्ण को दूरस्थ पक्ष में भेज दिया जाता है, जहां दूरस्थ छद्म-टर्मिनल का लाइन अनुशासन दूरस्थ कमांड को व्यवधान भेजता है ।

जब तुम करोगे:

ssh -t host seq 3

seq 31\n2\n3\nअपने स्टडआउट को लिखते हैं , जो एक छद्म टर्मिनल डिवाइस है। इसकी वजह से onlcr, होस्ट करने के लिए इसका अनुवाद हो जाता है 1\r\n2\r\n3\r\nऔर आपको एन्क्रिप्टेड चैनल पर भेज दिया जाता है। आपकी ओर से कोई अनुवाद ( onlcrअक्षम) नहीं है, इसलिए 1\r\n2\r\n3\r\nअछूता ( rawमोड के कारण) प्रदर्शित होता है और आपके टर्मिनल विनियामक की स्क्रीन पर सही ढंग से दिखाई देता है।

अब, यदि आप करते हैं:

ssh -t host seq 3 > some-file

ऊपर से कोई अंतर नहीं है। sshएक ही बात लिखेंगे: 1\r\n2\r\n3\r\nलेकिन इस बार में some-file

इसलिए मूल रूप से सभी के LFउत्पादन seqमें अनुवाद किया CRLFगया है some-file

यदि आप ऐसा ही करते हैं:

ssh -t host cat remote-file > local-file

सभी LFवर्णों (0x0a बाइट्स) का CRLF (0x0d 0x0a) में अनुवाद किया जा रहा है।

शायद यही कारण है कि आपकी फ़ाइल में भ्रष्टाचार का कारण है। दूसरी छोटी फ़ाइल के मामले में, यह सिर्फ इतना होता है कि फ़ाइल में 0x0a बाइट्स नहीं होते हैं, इसलिए कोई भ्रष्टाचार नहीं है।

ध्यान दें कि आप अलग-अलग प्रकार की भ्रष्टाचार के साथ अलग-अलग प्रकार की सेटिंग प्राप्त कर सकते हैं। भ्रष्टाचार से जुड़ा एक और संभावित प्रकार -tहै, यदि आपकी स्टार्टअप फाइलें host( ~/.bashrc, ~/.ssh/rc...) उनके स्टाडर पर चीजें लिखती हैं, क्योंकि -tरिमोट शेल के स्टडआउट और स्टडर के साथ अंत में ssh's' स्टडआउट में विलय हो जाता है (वे दोनों छद्म में जाते हैं। -टर्मिनल डिवाइस)।

आप नहीं चाहते कि रिमोट catकिसी टर्मिनल डिवाइस को आउटपुट दे।

तुम्हें चाहिए:

ssh host cat remote-file > local-file

तुम यह कर सकते थे:

ssh -t host 'stty -opost; cat remote-file` > local-file

यही कारण है कि (छोड़कर काम करेगा लेखन stderr को भ्रष्टाचार मामले में ऊपर चर्चा), लेकिन फिर भी है कि उप इष्टतम किया जाएगा के रूप में आपको लगता है कि अनावश्यक छद्म टर्मिनल परत पर चल रहा होगा host


कुछ और मजेदार:

$ ssh localhost echo | od -tx1
0000000 0a
0000001

ठीक है।

$ ssh -t localhost echo | od -tx1
0000000 0d 0a
0000002

LF का अनुवाद किया CRLF

$ ssh -t localhost 'stty -opost; echo' | od -tx1
0000000 0a
0000001

ठीक है फिर से।

$ ssh -t localhost 'stty olcuc; echo x'
X

यह आउटपुट पोस्ट-प्रोसेसिंग का एक और रूप है जो टर्मिनल लाइन अनुशासन द्वारा किया जा सकता है।

$ 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सर्वर को एक छद्म टर्मिनल का उपयोग करने के लिए बताने से मना कर दिया जब उसका स्वयं का इनपुट टर्मिनल नहीं है। आप इसे -ttहालांकि के साथ मजबूर कर सकते हैं :

$ echo x | ssh -tt localhost 'stty -opost; echo' | od -tx1
0000000   x  \r  \n  \n
0000004

इनपुट साइड पर लाइन अनुशासन बहुत कुछ करता है।

यहाँ, echoइसके इनपुट को नहीं पढ़ा है और न ही आउटपुट के लिए कहा गया है कि x\r\n\nयह कहाँ से आता है? यह echoदूरस्थ छद्म टर्मिनल ( stty echo) का स्थानीय है । sshसर्वर खिला है x\nयह दूरदराज के छद्म टर्मिनल के मालिक ओर करने के लिए ग्राहक से पढ़ें। और उस पंक्ति का अनुशासन उसे वापस लाता है (पहले stty opostचलाया जाता है जिसके कारण हमें a CRLFऔर not दिखाई देता है LF)। यह इस बात से स्वतंत्र है कि दूरस्थ अनुप्रयोग स्टड से कुछ भी पढ़ता है या नहीं।

$ (sleep 1; printf '\03') | ssh -tt localhost 'trap "echo ouch" INT; sleep 2'
^Couch

0x3चरित्र के रूप में वापस गूँजती है ^C( ^और C) की वजह से stty echoctlऔर खोल और नींद क्योंकि एक SIGINT प्राप्त stty isig

इसलिए जबकि:

ssh -t host cat remote-file > local-file

काफी बुरा है, लेकिन

ssh -tt host 'cat > remote-file' < local-file

फ़ाइलों को दूसरे तरीके से स्थानांतरित करना बहुत बुरा है। > वामो अनुवाद, लेकिन यह भी सभी विशेष वर्ण के साथ समस्याओं (- आप कुछ सीआर मिल जाएगा ^C, ^Z, ^D, ^?, ^S...) और भी दूरदराज के catEOF नहीं देखेंगे के अंत जब local-fileतक पहुँच जाता है, जब ^Dएक के बाद भेज दिया जाता है \r, \nया किसी अन्य की ^Dतरह जब cat > fileअपने टर्मिनल में कर रहे हैं ।


5

फ़ाइल को कॉपी करने के लिए उस पद्धति का उपयोग करते समय फाइलें अलग-अलग दिखाई देती हैं।

रीमोट सर्वर

ls -l | grep vim_cfg
-rw-rw-r--.  1 slm slm 9783257 Aug  5 16:51 vim_cfg.tgz

स्थानीय सर्वर

अपना ssh ... catआदेश चलाना :

$ ssh dufresne -t 'cat ~/vim_cfg.tgz' > vim_cfg.tgz

स्थानीय सर्वर पर इस फ़ाइल में परिणाम:

$ ls -l | grep vim_cfg.tgz 
-rw-rw-r--. 1 saml saml 9820481 Aug 24 12:13 vim_cfg.tgz

जांच क्यों?

स्थानीय पक्ष पर परिणामी फ़ाइल की जांच से पता चलता है कि यह दूषित हो गया है। यदि आप -tअपने sshकमांड से स्विच को बाहर निकालते हैं तो यह अपेक्षा के अनुरूप काम करता है।

$ ssh dufresne 'cat ~/vim_cfg.tgz' > vim_cfg.tgz

$ ls -l | grep vim_cfg.tgz
-rw-rw-r--. 1 saml saml 9783257 Aug 24 12:17 vim_cfg.tgz

चेकसम अब भी काम करते हैं:

# remote server
$ ssh dufresne "md5sum ~/vim_cfg.tgz"
9e70b036836dfdf2871e76b3636a72c6  /home/slm/vim_cfg.tgz

# local server
$ md5sum vim_cfg.tgz 
9e70b036836dfdf2871e76b3636a72c6  vim_cfg.tgz

शुक्रिया सिम। हालांकि वास्तव में आप सही उत्तर पोस्ट करने वाले पहले व्यक्ति थे, मैंने उनके स्पष्टीकरण की गहराई के कारण चुने हुए उत्तर के लिए स्टीफन का चयन किया। चिंता न करें, आपको एक लंबा पोस्ट इतिहास मिला है, जिससे मैं सीख रहा हूं, और निश्चित रूप से मैं उन पदों को बढ़ाता हूं, जिनसे मैं सीखता हूं। धन्यवाद।
dotancohen

@dotancohen - कोई चिंता नहीं है, आप स्वीकार करते हैं जो कभी भी आपको लगता है कि आप वही हैं जो आपको ओपी के रूप में सबसे अधिक 8- मदद करते हैं)। गाइल्स के अलावा चीजें क्यों होती हैं, यह स्पष्ट करने की उनकी क्षमता है।
स्लम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.