터미널에서 줄 바꿈없이 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
    • 라인 제어가 바로 뒤 따르는 입력 문자에 관한 한 특별한 의미를 제거합니다.

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

유사하게 처리되지만 임의의 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.