나는 종종 스크립트를 실행하고 여기에 STDIN 몇 줄을 입력해야 합니다. 이 작업을 수행할 때 일반적으로 통화를 준비한 다음 한 터미널 창에서 다른 터미널 창으로 복사하여 붙여넣습니다. 이상적으로는 다음과 같은 텍스트 블록을 붙여넣을 수 있기를 바랍니다.
<script name> <script args>
<STDIN line 1>
<STDIN line 2>
...
그런 다음 Ctrl-d를 눌러 STDIN이 입력 끝에 도달했음을 스크립트에 표시합니다.
bash에서 (단일 붙여넣기로) 이 작업을 수행하면 세션에서 STDIN 에코 없이 스크립트가 실행되고 <cr>
^d가 처리되기 전에 추가 항목이 적중되어야 하며 스크립트 STDIN의 첫 번째 줄이 손실됩니다. 그래서 보통 스크립트 호출을 자체 붙여넣기로 붙여넣은 다음 STDIN의 모든 줄을 두 번째 붙여넣기로 붙여넣습니다. 이렇게 하면 줄을 붙여넣고 에코할 수 있으며 Ctrl-d를 눌러 입력 끝을 나타낼 수 있습니다.
zsh에서 이 작업을 수행하면 대부분의 STDIN 줄이 에코되지 않습니다(STDIN 줄이 많으면 마지막 줄 중 일부가 에코되며 첫 번째 줄은 줄의 후행 조각만 에코할 수 있음). , <cr>
^d 이전에 추가 필요를 식별한 후.
문제의 스크립트가 Python인지 Perl인지는 중요하지 않습니다. 둘 다 동일하게 작동하므로 이것이 쉘 문제라고 믿게 됩니다.
문제는 문제가 어디에 있으며 각 실행을 단일 붙여넣기로 수행할 수 있는 솔루션이 있습니까?입니다.
실행되는 스크립트의 내용은 실제로 중요하지 않습니다. 내 테스트에서는 while 루프만큼 간단한 스크립트를 사용하여 STDIN을 한 줄씩 버퍼로 읽은 다음 while 루프 외부에 버퍼를 인쇄했습니다. 내가 말하는 것은 <cr>
키보드의 키에 따라 Enter 또는 Return 키입니다.
답변1
heredoc을 사용해 보세요. 잘라내고 붙여넣기가 쉽습니다.
script.sh arg arg arg <<'END_INPUT'
line1
line2
line3
END_INPUT
답변2
아마도 관찰 내용은 다음에 따라 달라집니다.라인 편집그리고 쉘은 터미널의 모드를 설정합니다.
텍스트를 붙여넣을 때
cat
a
b
("b" 뒤의 개행 포함)을 대화형 Bash 세션의 명령줄에 추가하면 기본적으로 다음에서 설정을 찾을 수 있습니다.오리지널 모드— 행을 편집할 때와 같습니다.GNU 읽기 라인라이브러리는 무엇보다도 입력이 한 줄씩이 아닌 문자별로 쉘에 전송되어 캐리지 리턴( , 를 \r
누를 때 터미널이 보는 내용 Enter또는 명령에 붙여넣을 때 줄바꿈을 변환함을 의미합니다. 행) 개행( \n
)은 비활성화되고 입력된 문자는 터미널이 아닌 쉘 자체에 의해 명령줄에 에코됩니다.
그런 다음 셸은 첫 번째 줄을 읽고 그것이 완전한 간단한 명령( cat
)임을 확인하고 실행합니다. 이 작업을 수행하는 동안 자체 라인 편집도 비활성화되고 터미널을 "cooked" 모드로 설정하고 \r
→ \n
변환을 활성화합니다. 그러나 이 시점에서 입력 버퍼에는 이미 화면에서 a\rb\r
읽고 인쇄된 내용이 포함되어 있습니다. 그런 다음 + ( )를 cat
누르면 종료되고 새 프롬프트가 인쇄되며 (유일한) 인쇄된 줄을 덮어씁니다(캐리지 리턴으로 끝나기 때문입니다).CtrlD^D
cat
알아채다:
대신
cat
루프에서 표준 입력을 읽는 프로그램을 호출하면 스크립트와 동일합니다.while IFS= read -r foo do # Accumulate the content of foo done
Enter입력 버퍼에 문자가 없기 때문에 클릭할 때까지 아무 것도 읽지 않습니다
\n
(붙여넣은 데이터가 터미널의 입력 버퍼 크기를 초과하지 않는 한, 아래 참조).b
붙여넣은 후 명령 뒤에 표시되는 텍스트(이 경우)는 붙여넣은 내용의 에코가 아니라cat
. 예를 들어 붙여넣기를 통해 이를 쉽게 확인할 수 있습니다.od -An -tc a b
쉘 실행에 붙여넣는 것도
strace -f -e read,write bash
무슨 일이 일어나고 있는지 이해하는 데 도움이 될 수 있습니다.표준 입력에서 읽을 붙여넣은 텍스트가 "충분"한 경우(내 시스템에서는 4095자 이상, "정규 및 비정규 모드" 참조)
man 3 termios
), 위에 작성된 내용은 처음 4095바이트 크기 읽기에만 적용됩니다. 이는 터미널이 원시 모드에서 입력 버퍼에 넣는 최대량입니다. 이후 읽기는 베이킹 모드에서 발생하고\r
→\n
변환이 발생하며 붙여넣은 텍스트의 해당 부분이 명령줄에 반영됩니다(명령의 출력과 혼합될 수 있음).
원칙적으로 Bash의 줄 편집을 비활성화하면 이 동작을 변경할 수 있습니다.
$ set +o emacs
$ set +o vi
$ cat # Pasting the above snippet here
a
b
a
b
$ # ^D makes cat exit and brings the prompt back
그러나 "대괄호 붙여넣기"가 활성화되지 않는 한(아래 참조) 처리를 시작하기 전에 붙여넣기 작업이 끝날 때까지 기다리도록 터미널에서 쉘에 지시할 방법이 없기 때문에 긴 입력은 여전히 출력과 혼합됩니다.
zsh
조금 더 간단한 것 같습니다. 유일한 문제:"괄호 안에 붙여넣기"기본적으로 활성화될 수 있습니다. 이를 통해 여러 줄 명령을 명령줄에 붙여넣고 특수 문자(예: 탭, 줄 바꿈)가 올바르게 처리되는지 확인하면서 스크립트처럼 실행할 수 있습니다. 이는 또한 주어졌을 때
cat
a
b
zsh
세 줄을 읽고 실행하며 cat
종료 시 터미널에서 새 입력을 기다리고 cat
쉘이 실행을 시도한 a
다음(해당 명령이 시스템에 존재하지 않으면 실패함) b
.
대괄호 붙여넣기를 비활성화하면 원하는 동작이 달성됩니다(그러나 bash
줄 없는 편집과 달리 zsh
붙여넣은 내용은 처음 4095바이트를 초과하는 부분을 제외하고 기본적으로 에코되지 않습니다(목록 위의 글머리 기호 참조)).
% unset zle_bracketed_paste
% cat # Pasting the above snippet here
a # cat prints these two lines
b
% # ^D makes cat exit and brings the prompt back