특정 명령은 특정 터미널 창에서 지속적으로 실패하기 시작합니다.
$ sudo apt-get install ipython
...
After this operation, 3,826 kB of additional disk space will be used.
Do you want to continue? [Y/n] Abort.
$
$ kinit -f <username>
Password for <username>@<domain>:
kinit: Pre-authentication failed: Cannot read password while getting initial credentials
$
$ passwd
Changing password for <username>.
(current) UNIX password:
passwd: Authentication token manipulation error
passwd: password unchanged
$
$ crontab -e
Too many errors from stdincrontab: "/usr/bin/sensible-editor" exited with status 1
$
$ sudo docker run -it ubuntu bash
(hangs forever)
원인을 찾는 과정에서,스트레스디스플레이 프로그램이 STDIN에서 읽으려고 시도했지만 오류가 발생했습니다.
read(0, 0x7fffe1205cc7, 1) = -1 EAGAIN (Resource temporarily unavailable)
~에서독서(2)매뉴얼 페이지:
ERRORS
EAGAIN The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read would block.
물론 터미널 창의 STDIN은 비차단으로 표시됩니다(4로 표시됨).배너):
$ cat /proc/self/fdinfo/0
pos: 0
flags: 0104002
mnt_id: 25
나는 내가 사용하고 있는 일부 프로그램이 STDIN을 비차단 모드로 설정한 다음 종료 시 다시 설정하지 않는다고 가정합니다(또는 가능하기 전에 종료됩니다).
저는 명령줄에서 이 문제를 해결하는 방법을 몰랐기 때문에 이를 수행하기 위해 다음 프로그램을 작성했습니다. (또한 STDIN을 비차단 모드로 변경하여 무엇이 잘못되었는지 확인할 수 있습니다.)
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int makeStdinNonblocking(int flags) {
if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) < 0) {
printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int makeStdinBlocking(int flags) {
if (fcntl(STDIN_FILENO, F_SETFL, flags & ~(O_NONBLOCK)) < 0) {
printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int main(int argc, char *argv[]) {
int flags;
if (argc != 2) {
goto usage;
}
if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0) {
printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
return EXIT_FAILURE;
}
if (0 == strncmp(argv[1], "nonblock", 9)) {
return makeStdinNonblocking(flags);
}
else if ( 0 == strncmp(argv[1], "block", 6)) {
return makeStdinBlocking(flags);
}
usage:
printf("Usage: %s <nonblock|block>\n", argv[0]);
return EXIT_FAILURE;
}
어쨌든, 나는 알고 싶습니다:
- 표준 명령줄 유틸리티를 사용하여 STDIN을 비차단으로 만드는 방법이 있습니까?
- 쉘(내 경우에는 bash)이 명령 사이의 STDIN(및/또는 STDOUT/STDERR)에 대한 플래그를 자동으로 복원해야 합니까? 다른 프로그램에서 수행한 STDIN 변경 사항에 의존하는 명령에 대한 사용 사례가 있습니까?
- 프로그램이 시작될 때 STDIN이 차단 모드에 있을 것이라고 가정하고 모든 프로그램이 문제를 일으킬 경우 비차단 모드를 특별히 꺼야 한다고 가정하는 것은 실수입니까(위의 예 참조)?
참고로 저는 Ubuntu 17.10 및 GNU bash 버전 4.4.12(1)-release(x86_64-pc-linux-gnu)를 사용하고 있습니다.
고쳐 쓰다: Fedora의 이 문제는 bash 패치로 수정된 것 같습니다.
https://bugzilla.redhat.com/show_bug.cgi?id=1068697
그러나 이 수정 사항은 적어도 버전 4.4.18(1) 릴리스(2018년 1월부터)에서는 업스트림에 적용된 것으로 보이지 않습니다. 또한 bash 관리자는 bash가 이에 대해 실제로 책임을 지지 않는다고 언급했습니다.
https://lists.gnu.org/archive/html/bug-bash/2017-01/msg00043.html
애플리케이션이 STDIN의 원래 플래그를 변경하면 해당 플래그를 복원해야 하는 것처럼 들리므로 다음 절차를 사용하여 STDIN을 확인합니다.
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
int flags;
if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0) {
printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
}
if (0 != (flags & (O_NONBLOCK))) {
printf("Warning, STDIN in nonblock mode\n");
}
return EXIT_SUCCESS;
}
나는 프로그램( gcc -o checkstdin checkstdin.c
)을 컴파일한 다음 각 명령 후에 실행되도록 .bashrc에 다음을 넣었습니다.
PROMPT_COMMAND+="/path/to/checkstdin"
STDIN이 현재 비차단 모드에 있음을 감지하면 STDOUT에 경고를 인쇄합니다.
답변1
이런 일이 발생하면 명령줄에서 bash를 실행하고 종료합니다(첫 번째 bash로 돌아갑니다). 다시 작동해야 합니다. 다음은 몇 가지 흥미로운 세부정보입니다.https://stackoverflow.com/questions/19895185/bash-shell-read-error-0-resource-temporarily-unavailable.
답변2
해결 방법을 스크립팅해야 하는 경우 다음을 사용할 수 있습니다.
perl -MFcntl -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) & ~O_NONBLOCK'