터미널에서 줄 바꿈없이 4k 이상의 입력을 읽는 방법은 무엇입니까?


25

그래서 클립 보드에 새로운 라인 이없는 많은 데이터가 있습니다 (한 줄에 큰 SVG 파일입니다). 나는 갔다

$ cat >file.svg

그런 다음 (Gnome Terminal에서) 붙여 넣기를 시도했지만 처음 4kB 문자 만 허용되었습니다.

이것이 readline 기능 / 제한이라고 가정합니다.

이 문제를 피할 수있는 STDIN에서 읽을 수있는 방법이 있습니까?

편집하다

테스트 사례 : 데모 파일을 만듭니다. 이것은 ~ 4k "="기호와 "foo bar"를 갖습니다.

{ printf '=%.0s' {1..4095} ; echo "foo bar" ; } > test.in

클립 보드에 복사

xclip test.in

(중간 클릭하여 삽입하려는 경우) 또는

xclip -selection clipboard test.in

(Ctrl-Shift-Insert를 사용하여 붙여 넣으려면)

그런 다음 cat >test.out붙여 넣습니다 (어느 쪽이든). 스트림을 종료하려면 Ctrl-D를 누르십시오. cat test.out- "foo bar"가 보입니까?

붙여 넣을 때 내 설정 (Ubuntu 12.04, Gnome Terminal, zsh)에서 만 볼 수 =있고 보이지 않습니다 foo bar. 검사 할 때도 동일합니다 test.out.


SVG 파일을 클립 보드로 완전히 읽었습니까?
lgeorget

실제 문제는 무엇입니까? 클립 보드의 내용을 파일로 저장하는 방법? 그렇다면 터미널에 붙여 넣기 이외의 방법이 있습니다.
lgeorget

귀하의 경우 N은 얼마입니까? 2kB의 xml 데이터 (inc LF)로 문제를 시도하지 않았습니다.
fduff

1
@artfulrobot 포 그라운드 프로세스는 tty / pty와 직접 상호 작용합니다. 껍질은 관여하지 않습니다. 프로그램에서 readline 또는 다른 입력 라이브러리를 사용하지 않는 경우 readline 기능 (편집 / 점프 명령, 히스토리 등)이 없기 때문에이를 확인할 수 있습니다.
jofel

1
이것은 readline 제한이 아니며 readline 및 bash는 여기에 포함되지 않습니다. 터미널 인터페이스의 한계입니다.
Gilles 'SO- 악마 그만해'

답변:


22

소스를 올바르게 이해하면 Linux에서 터미널에서 한 번에 읽을 수있는 최대 문자 수 N_TTY_BUF_SIZE는 커널 소스에 의해 결정됩니다 . 값은 4096입니다.

이것은 터미널 인터페이스, 특히 정식 ( "요리 된") 모드 의 한계로, 매우 조잡한 라인 편집기를 제공합니다 ( 파일 끝 행 시작시 백 스페이스, Enter, Ctrl+ D). 그것은 읽고있는 프로세스 외부에서 발생합니다.

터미널을 원시 모드로 전환하여 라인 처리를 비활성화 할 수 있습니다. 또한 Ctrl+ D및 기타 기능을 비활성화 하여 프로그램에 추가 부담을줍니다.

이것은 동기 부여가 거의 없기 때문에 수정되지 않은 고대 유닉스 제한입니다. 인간은 그런 긴 줄에 들어 가지 않습니다. 프로그램에서 입력을 공급하는 경우 파일 또는 파이프에서 프로그램 입력을 리디렉션합니다.

예를 들어 X 클립 보드의 내용을 사용하려면 xsel또는 에서 파이프하십시오 xclip. 귀하의 경우 :

xsel -b >file.svg
xclip -selection clipboard >file.svg

클립 보드 대신 X 선택 항목 (마우스로 강조 표시 한 설정)을 제거 -b하거나 -selection clipboard사용하십시오.

OSX에서는 pbpaste클립 보드 내용을 붙여넣고 pbcopy설정하는 데 사용하십시오.

ssh -X(일부 서버에서는 금지 할 수 있음) 을 사용하여 X11 전달을 활성화하면 SSH를 통해 X 클립 보드에 액세스 할 수 있습니다 . 만 사용할 수있는 경우 sshX11 포워딩하지 않고, 당신이 사용할 수있는 scp, sftp또는 sshfs파일을 복사 할 수 있습니다.

클립 보드를 전달할 수 없거나 붙여 넣기를 할 수는 없지만 가상 머신에 입력하는 것을 방지 할 수 있기 때문에 붙여 넣기가 유일한 솔루션 인 경우 대체 방법은 데이터를 줄 바꿈이있는 것으로 인코딩하는 것입니다. Base64 는 이에 적합합니다. 임의의 데이터를 인쇄 가능한 문자로 변환하고 디코딩 할 때 공백을 무시합니다. 이 접근 방식은 입력시 임의의 데이터를 지원하고 붙여 넣을 때 터미널이 해석 할 제어 문자도 추가한다는 이점이 있습니다. 귀하의 경우 콘텐츠를 인코딩 할 수 있습니다.

xsel -b | base64 | xsel -b

그런 다음 해독하십시오.

base64 -d
 Paste
Ctrl+D

xsel> 4k 바이트와 함께 사용할 때 데이터가 심하게 손상되는 버그가 있습니다 : github.com/kfish/xsel/issues/14
Patrick

14

당신이로 실행중인 한계가있는 행의 최대 크기입니다 정규 입력 모드 , MAX_CANON.

표준 입력 모드에서 tty 드라이버는 기본 라인 편집 서비스를 제공하므로 사용자 공간 프로그램이 필요하지 않습니다. readline만큼 많은 기능을 가지고 있지는 않지만 삭제 (일반적으로 Backspace 또는 Delete) 및 kill (보통 Ctrl-U)과 같은 구성 가능한 특수 문자를 인식합니다.

귀하의 질문에 가장 중요한 것은 라인 끝 문자가 보일 때까지 표준 모드 버퍼 입력입니다. 버퍼는 tty 드라이버, 커널 메모리에 있기 때문에 크지 않습니다.

stty cbreak또는로 표준 모드를 ​​끈 stty -icanon다음 붙여 넣기를 수행 할 수 있습니다. 이것은 Ctrl-D로 EOF를 보낼 수 없다는 중요한 단점이 있습니다. 이것이 표준 모드가 담당하는 또 다른 것입니다. cat신호 생성 문자는 별도의 플래그 ( stty raw또는 stty -isig) 로 제어되므로 Ctrl-C를 사용 하여 계속 종료 할 수 있습니다 .

나에게 신비 왜, 당신은 이미 당신에 대해 알고있는 것을 증명 한 이후이다 xclip, 당신은 그냥 사용하지 않는 xclip -o > file의 대신cat


1
미스터리는 쉽게 해결할 수 있습니다. artfulrobot은 클립 보드의 데이터로 원격 호스트의 파일을 빠르게 채우려 고합니다. 원격 셸에서는 일반적으로 xclip을 통해 로컬 클립 보드에 직접 액세스 할 수 없습니다.
jofel

3
아, 붙여 넣기에 의한 오래된 업로드. 그 중 하나를 수행해야하고 일반 텍스트가 아닌 경우 tty 드라이버가 통과하도록 설득하려고 시도하는 대신 uuencode합니다. 거대한 줄이있는 일반 텍스트도 그렇게 처리 될 수 있습니다.

2

당신이 할 경우 :

stty eol =

다음에 제시된 데모 실행 편집을 , 당신은 볼 수 foo는 바 의 출력에 test.out . 터미널의 라인 원칙은 입력에서 각 특수 eol 문자를 읽을 때 출력을 리더로 플러시합니다 .

Linux 표준 모드 터미널 은 다음과 같은 특수 입력 문자를 처리 stty icanon하거나 구성 할 수 있습니다 stty sane.

  • eof
    • 태만: ^D
    • 입력 라인을 종료하고 출력을 리더로 플러시합니다. 입력에서 제거되므로 행에서 유일한 문자로 입력되면 읽기 또는 파일 끝으로 리더에 전달됩니다.
  • ol
    • 기본값 : 할당되지 않은
    • 또한 입력 라인을 종료하지만 입력에서 제거되지는 않습니다.
  • 죽이다
    • 태만: ^U
    • 버퍼링 된 모든 입력을 지 웁니다.
  • 삭제
    • 기본값 : ^H (또는 가능 @하거나 ^?일부 시스템에서)
    • 마지막으로 버퍼링 된 입력 문자를 지 웁니다.

iexten가 도 설정 -처럼에게 stty icanon iexten또는, 다시, 아마 stty sane, 정식 리눅스 터미널도 처리 할 ...

  • eol2
    • 기본 : 할당되지 않은
    • 또한, 또한 , 입력 라인을 종료하고, 또한 입력에서 제거되지.
  • 웨 라세
    • 태만: ^W
    • 마지막으로 버퍼링 된 입력 단어를 지 웁니다 .
  • rprnt
    • 태만: ^R
    • 버퍼링 된 모든 입력을 재 인쇄합니다.
  • 다음
    • 태만: ^V
    • 라인 제어가 바로 뒤 따르는 입력 문자에 관한 한 특별한 의미를 제거합니다.

이러한 문자는 입력 스트림에서 제거하고 ( eoleol2 제외) , 즉 처리 된 스트림을 리더로 전달하기 전에 연관된 특수 기능을 수행합니다 (일반적으로 쉘이지만 포 그라운드 프로세스 그룹이 될 수 있음). .

유사하게 처리되지만 임의의 icanon 설정과 독립적으로 구성 할 수있는 다른 특수 입력 문자 는 isig 세트 stty isig를 포함하며 아마도 제정신 구성 에도 포함될 수 있습니다.

  • 떠나다
    • 태만: ^\
    • 버퍼링 된 모든 입력을 플러시하고 ( noflsh 가 설정되지 않은 경우 ) SIGQUIT를 포 그라운드 프로세스 그룹으로 보냅니다. 코어 덤프가 생성 될 수 있습니다.
  • 서스펜션
    • 태만: ^Z
    • 버퍼링 된 모든 입력을 플러시하고 ( noflsh 가 설정되지 않은 경우 ) SIGTSTP를 포 그라운드 프로세스 그룹으로 보냅니다. 일시 중단 된 프로세스 그룹은 가능성 중 하나를 사용하여 다시 시작할 수 있습니다 kill -CONT "$!"하거나 fgA의 ( set -m) 작업 제어 쉘.
  • intr
    • 태만: ^C
    • 버퍼링 된 모든 입력을 플러시하고 ( noflsh 가 설정되지 않은 경우 ) SIGINT를 포 그라운드 프로세스 그룹으로 보냅니다.

그리고 IXON의 세트 - 같은 구성 stty ixon도 보통에 포함 제정신의 설정 :

  • 중지
    • 태만: ^S
    • 입력에서 시작 을 읽을 때까지 또는 ixany 가 설정되어 있을 때 하나 이상의 문자를 읽을 때까지 리더에 대한 모든 출력을 중지합니다 .
  • 스타트
    • 태만: ^Q
    • stop으로 이전에 중지 된 경우 출력을 다시 시작합니다 .
  • 처리시 중지시작 이 모두 입력에서 제거되지만 ixany 가 설정 될 때 입력 문자로 인해 출력이 다시 시작되면 해당 문자가 제거되지 않습니다.

Linux 이외의 다른 시스템에서 처리되는 특수 문자에는 다음이 포함될 수 있습니다.

  • 플러시
    • 태만: ^O
    • 버퍼링 된 입력의 삭제 및 플러시를 토글하고 입력에서 제거됩니다.
  • dsusp
    • 기본 : 할당되지 않은
    • 리더가 지정된 특수 입력 문자를 읽은 다음 SIGTSTP를 보낼 때만 버퍼링 된 모든 입력을 플러시합니다.

그리고 아마도 ...

  • swtch
    • 기본값 ^@ ( \0또는 의미 NUL)
    • 포 그라운드 쉘 레이어를 전환합니다. 일부 시스템 에서 shl 쉘 계층 응용 프로그램 과 함께 사용 합니다.
    • 의 구현 shl멀티 플렉스의 ptys 및 작업 제어가 아닌 원래의 구현의과 호환되는 에서 swtch 의존 동작은 자유롭게에서 가지게 될 수있다 heirloom-toolchest툴 스위트.

이러한 입력 기능을 처리 하는 방법과 이유 (및 어쩌면 왜 그렇지 않은지)에 대한 명확한 그림을 보려면를 참조하십시오 man 3 termios.

적용 가능한 경우 위의 모든 기능을 할당 (또는 재 할당) 할 수 있습니다 sttyfunction assigned-key. 단일 기능을 비활성화하려면을 수행하십시오 . GNU, AST, 또는 가보의 모든과 상기 라인 편집의 모든 기능에 대한 과제와 다양한 시도로 또는 구현을 표시하는 것, 당신은 또한 수 로 NUL의 모든 기능에 대한 할당으로 설정 동일시하는 것 같다 할당되지 않은 내 리눅스에 체계.sttyfunction^-sttysttyfunction^@

아마 당신이 입력 할 때이 문자 들의 에코 를 보았을 것입니다 ( [-] ctlecho 로 구성 될 수 있습니다 ) . 그러나 이것은 당신이 어디에서했는지 보여주기위한 마커 일뿐입니다-입력을받는 프로그램은 그것들을 입력하고 ( 즉, eol [2] 제외 ) , 선 분야가 효과를 적용한 입력 사본 만받습니다.

터미널이 다양한 라인 편집 기능을 처리 한 결과, 사용자가 지시 한 기능을 수행하기 위해 입력을 어느 정도 버퍼링해야하므로 입력의 무한한 공급이 불가능합니다. 당신은 언제든지 죽일 수 있습니다. 라인 버퍼는 더 정확하게이다 버퍼입니다.

당신은 설정하면 EOL 또는 EOL2 둘 줄 바꿈 또는 리턴 문자, 예를 들면없는 경우에도 - - 당신은 할 수있을 것입니다 입력에서 발생하는 일부 구분 문자 죽일 가 마지막으로 발생하는 시점까지가 당신의 버퍼 이 중 다음 줄 또는 개행 (또는 icrnl 이 설정되고 igncr설정 되지 않은 경우 리턴 ) 까지 입력에서 입력 될 때까지 확장됩니다 .


1

cat예를 들어 목격 할 수있는 것처럼 많은 수의 문자를 허용합니다 cat /dev/random > test.bin(중지하는 방법을 모르면 수행하지 마십시오 :). 큰 파일 을 복사하여 붙여 넣으려고 했습니다 cat > test.txt. Ctrl- c또는 Ctrl-로 취소했는지 여부에 관계없이 모든 줄이 파일 d에 들어 갔지만 전자의 경우 모든 줄이 터미널에 인쇄 된 것은 아닙니다 . 이것은 cat인쇄를 버퍼링하여 텍스트의 전체 버퍼를 기다리거나 각 인쇄 전에 터미널에서 직접 입력하기 때문입니다.

필자의 시스템에서는 버퍼 크기는 4096 (2 ^ 12) 바이트 생각 : 사용하여 4095 바이트의 파일을 작성 (printf '1234567890%.0s' {1..409} && printf 12345) > test.in복사본으로 사용하여 버퍼 것으로, 부하를 xclip test.in시작 cat > test.out사용하여 붙여 넣기 Shift- Insert,를 눌러 스트림을 종료 Ctrl- d. 이제를 사용하여 바이트를 추가 printf '6' >> test.in하면 스트림이 두 번 인쇄 됩니다 . cat출력 (한 4096 바이트)에 도달하면 종료 후 쉘 에서 마지막 4095 바이트를 다시 입력 합니다.


+1 제 경우에는 사용 된 클립 보드에도 의존했습니다. 선택 버퍼 (중간 클릭 붙여 넣기)를 사용하면 테스트 데이터의 첫 4542 줄 만 보았지만 모든 파일이 만들어진 파일로 끝났지 만 X 클립 보드 (Ctrl + C / Ctrl + V)를 사용했습니다. 그것의 모든. 두 경우 모두 모든 데이터가 결과 파일로 인쇄되었지만 전자의 경우 일부 데이터 만 터미널에 표시되었습니다.
terdon

1
나는 같은 행동을하지 않습니다. 수정 된 질문보기
artfulrobot 12

0

해결책은 vim과 같이 긴 줄을 지원하는 편집기에 붙여 넣는 것입니다.

vim을 사용하는 경우 텍스트를 :paste삽입 i하고 붙여 넣기 모드로 들어가기 전에 먼저 붙여 넣기 모드로 들어가십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.