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

时间:2013-11-10 21:04:55

标签: bash shell

编写bash脚本时。有时你正在运行一个命令,打开另一个程序,如npm,composer ..等。但同时你需要使用read来提示用户。

你不可避免地遇到了这种错误:

read: read error: 0: Resource temporarily unavailable

在做了一些研究之后,似乎有一个解决办法,就是将那些操作bash脚本的STDIN的程序的STDIN用于/ dev / null。

类似的东西:

npm install </dev/null

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

问题是有某种傻瓜证明,优雅的方式来阅读用户提示输入而不受那些操纵STDIN的程序的影响,而不必寻找哪些程序需要将其STDIN重定向到/ dev / null。您甚至可能需要使用这些程序的STDIN!

6 个答案:

答案 0 :(得分:6)

通常,知道调用的程序所期望的输入以及从哪里开始是很重要的,因此从/ dev / null重定向stdin对于那些不应该获取任何内容的人来说不是一个问题。

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

exec 3<&0 0</dev/null

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

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

read -r var 0<&3

<重定向运算符假定目标文件描述符为0,如果省略,则上述两个命令可以这样写:

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

答案 1 :(得分:5)

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

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

或与spbnick的回答结合:

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

3中为read留下一个干净的STDIN,0和{{1}}成为命令终端的新流。

答案 2 :(得分:2)

当发生这种情况时,从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

答案 3 :(得分:1)

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

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

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

您也可以让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')'

答案 4 :(得分:1)

我有同样的问题。我这样解决,方法是直接从tty读取,重定向标准输入:

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

而不是简单地:

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

就我而言,使用exec 3<&0 ...无效。

答案 5 :(得分:1)

很显然(资源暂时不可用,是EAGAIN),这是由退出程序却使STDIN处于nonblocking模式的程序引起的。 这是另一种解决方案(最容易编写脚本?):

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