TL; DR
를 사용하지 마십시오 -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
있습니다.
실제로 발생하는 것은 stdout이 파이프로 경로 재 지정된 상태 에서 seq 3
명령이 실행되는 것 host
입니다. ssh
호스트 의 서버는 파이프의 다른 쪽 끝을 읽고이를 암호화 된 채널을 통해 ssh
클라이언트로 전송하고 ssh
클라이언트는 stdout에 기록합니다.이 경우 의사 터미널 장치는 LF
s가 CRLF
표시 되도록 변환 됩니다.
stdout이 터미널이 아닌 경우 많은 대화식 응용 프로그램이 다르게 작동합니다. 예를 들어, 다음을 실행하는 경우 :
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 3
1\n2\n3\n
의사 터미널 장치 인 stdout에 씁니다 . 의 때문에 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 바이트가 포함되어 있지 않으므로 손상이 없습니다.
다른 tty 설정으로 다른 유형의 손상이 발생할 수 있습니다. 과 관련된 부패의 또 다른 잠재적 인 유형 -t
인 경우에 당신의 시작 파일 host
( ~/.bashrc
, ~/.ssh/rc
...) 때문에 그들의 표준 에러에 대한 쓰기 것들 -t
에 병합되는 최대 stdout 및 원격 쉘 끝의 열려진 ssh
표준 출력의 (의사로 이동 둘 터미널 장치).
리모컨 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
를 보지 말아야합니다 LF
). 그것은 원격 응용 프로그램이 stdin에서 무엇이든 읽는지 여부와 관계가 없습니다.
$ (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
다른 방법으로 파일을 전송하는 것은 훨씬 더 나쁩니다. 모든 특수 문자> LF 번역뿐만 아니라 문제 (- 당신은 몇 가지 CR 얻을 것이다 ^C
, ^Z
, ^D
, ^?
, ^S
...) 또한 리모콘 cat
의 마지막 때 EOF 표시되지 않습니다 local-file
에 도달 할 때이 경우에만 ^D
이후에 전송되는 정보 \r
, \n
또는 터미널에서 할 ^D
때와 같은 다른 것 cat > file
.
-t
전송을 중단 시키는 옵션입니다. 사용하지 마십시오-t
또는-T
당신은 매우 구체적인 이유를 필요로하지 않는 한,. 기본값은 대부분의 경우에 작동하므로 이러한 옵션은 거의 필요하지 않습니다.