Bash shell 读取错误:0:资源暂时不可用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19895185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 08:35:04  来源:igfitidea点击:

Bash shell read error: 0: Resource temporarily unavailable

bashshell

提问by CMCDragonkai

When writing a bash script. Sometimes you are running a command which opens up another program such as npm, composer.. etc. But at the same time you need to use readin order to prompt the user.

编写 bash 脚本时。有时您运行的命令会打开另一个程序,例如 npm、composer.. 等。但同时您需要使用read以提示用户。

Inevitable you hit this kind of error:

难免会遇到这样的错误:

read: read error: 0: Resource temporarily unavailable

After doing some research there seems to be a solution by piping the STDIN of those programs which manipulate the STDIN of your bash script to /dev/null.

在做了一些研究之后,似乎有一个解决方案,就是将那些操纵 bash 脚本的 STDIN 的程序的 STDIN 传送到 /dev/null。

Something like:

就像是:

npm install </dev/null

Other research has shown it has something to do with the fact that the STDIN is being set to some sort of blocking/noblocking status and it isn't being reset after the program finishes.

其他研究表明,这与 STDIN 被设置为某种阻塞/无阻塞状态并且在程序完成后没有被重置的事实有关。

The question is there some sort of fool proof, elegant way of reading user prompted input without being affected by those programs that manipulate the STDIN and not having to hunt which programs need to have their STDIN redirected to /dev/null. You may even need to use the STDIN of those programs!

问题是有一些简单的、优雅的方式来读取用户提示的输入,而不受那些操作 STDIN 的程序的影响,也不必寻找哪些程序需要将其 STDIN 重定向到 /dev/null。您甚至可能需要使用这些程序的 STDIN!

采纳答案by spbnick

Usually it is important to know what input the invoked program expects and from where, so it is not a problem to redirect stdin from /dev/null for those that shouldn't be getting any.

通常,重要的是要知道被调用的程序期望什么输入以及从哪里输入,因此对于那些不应该获得的输入,从 /dev/null 重定向 stdin 不是问题。

Still, it is possible to do it for the shell itself and all invoked programs. Simply move stdin to another file descriptor and open /dev/null in its place. Like this:

尽管如此,还是可以为 shell 本身和所有调用的程序执行此操作。只需将 stdin 移动到另一个文件描述符并在其位置打开 /dev/null 即可。像这样:

exec 3<&0 0</dev/null

The above duplicates stdin file descriptor (0) under file descriptor 3 and then opens /dev/null to replace it.

上面复制了文件描述符 3 下的 stdin 文件描述符 (0),然后打开 /dev/null 替换它。

After this any invoked command attempting to read stdin will be reading from /dev/null. Programs that should read original stdin should have redirection from file descriptor 3. Like this:

在此之后,任何试图读取 stdin 的调用命令都将从 /dev/null 读取。应该读取原始标准输入的程序应该从文件描述符 3 重定向。像这样:

read -r var 0<&3

The <redirection operator assumes destination file descriptor 0, if it is omitted, so the above two commands could be written as such:

所述<重定向操作假定目的地文件描述符0,如果省略它,因此,上述两个命令可以写成这样:

exec 3<&0 </dev/null
read -r var <&3

回答by zenwheel

I had a similar issue, but the command I was running did need a real STDIN, /dev/null wasn't good enough. Instead, I was able to do:

我有一个类似的问题,但我运行的命令确实需要一个真正的 STDIN,/dev/null 不够好。相反,我能够做到:

TTY=$(/usr/bin/tty)
cmd-using-stdin < $TTY
read -r var

or combined with spbnick's answer:

或结合 spbnick 的回答:

TTY=$(/usr/bin/tty)
exec 3<&0 < $TTY
cmd-using-stdin
read -r var 0<&3`

which leaves a clean STDIN in 3for you to readand 0becomes a fresh stream from the terminal for the command.

3为您留下了一个干净的标准输入,read0成为来自终端的命令的新流。

回答by Oliver

When this happens, run bash from within your bash shell, then exit it (thus returning to the original bash shell). I found a mention of this trick in https://github.com/fish-shell/fish-shell/issues/176and it worked for me, seems like bash restores the STDIN state. Example:

发生这种情况时,请从 bash shell 中运行 bash,然后退出它(从而返回到原始 bash shell)。我在https://github.com/fish-shell/fish-shell/issues/176 中发现了这个技巧的提及,它对我有用,似乎 bash 恢复了 STDIN 状态。例子:

bash> do something that exhibits the STDIN problem
bash> bash
bash> exit
bash> repeat something: STDIN problem fixed

回答by hackerb9

The answers here which suggest using redirection are good. Fortunately, Bash's readshould soon no longer need such fixes. The author of Readline, Chet Ramey, has already written a patch: http://gnu-bash.2382.n7.nabble.com/read-may-fail-due-to-nonblocking-stdin-td18519.html

这里建议使用重定向的答案很好。幸运的是,Bashread应该很快就不再需要这样的修复了。Readline 的作者 Chet Ramey 已经写了一个补丁:http: //gnu-bash.2382.n7.nabble.com/read-may-fail-due-to-nonblocking-stdin-td18519.html

However, this problem is more general than just the readcommand in Bash. Many programs presume stdin is blocking (e.g., mimeopen) and some programs leave stdin non-blocking after they exit (e.g., cec-client). Bash has no builtin way to turn off non-blocking input, so, in those situations, you can use Python from the command line:

但是,这个问题比readBash 中的命令更普遍。许多程序假定 stdin 是阻塞的(例如,mimeopen),并且一些程序在退出后让 stdin 保持非阻塞状态(例如,cec-client)。Bash 没有关闭非阻塞输入的内置方法,因此,在这些情况下,您可以从命令行使用 Python:

$ python3 -c $'import os\nos.set_blocking(0, True)'

You can also have Python print the previous state so that it may be changed only temporarily:

您还可以让 Python 打印以前的状态,以便它只能暂时更改:

$ o=$(python3 -c $'import os\nprint(os.get_blocking(0))\nos.set_blocking(0, True)')
$ somecommandthatreadsstdin
$ python3 -c $'import os\nos.set_blocking(0, '$o')'

回答by linuxfan says Reinstate Monica

I had the same problem. I solved by reading directly from tty like this, redirecting stdin:

我有同样的问题。我通过像这样直接从 tty 读取来解决,重定向标准输入:

read -p "Play both [y]? " -n 1 -r </dev/tty

instead of simply:

而不是简单地:

read -p "Play both [y]? " -n 1 -r

In my case, the use of exec 3<&0 ...didn't work.

在我的情况下,使用exec 3<&0 ...没有用。

回答by niry

Clearly (resource temporarily unavailable is EAGAIN) this is caused by programs that exits but leaves STDINin nonblockingmode. Here is another solution (easiest to script?):

显然,(资源暂时不可用的EAGAIN),这是由程序引起的出口,但树叶STDINnonblocking模式。这是另一个解决方案(最容易编写脚本?):

perl -MFcntl -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) & ~O_NONBLOCK'