Bash shell read error: 0: Resource temporarily unavailable

后端 未结 6 2055
感情败类
感情败类 2021-02-07 23:54

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 read

相关标签:
6条回答
  • 2021-02-08 00:28

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

    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.

    0 讨论(0)
  • 2021-02-08 00:31

    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/176 and it worked for me, seems like bash restores the STDIN state. Example:

    bash> do something that exhibits the STDIN problem
    bash> bash
    bash> exit
    bash> repeat something: STDIN problem fixed
    
    0 讨论(0)
  • 2021-02-08 00:34

    The answers here which suggest using redirection are good. Fortunately, Bash's read should 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

    However, this problem is more general than just the read command 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:

    $ 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:

    $ 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')'
    
    0 讨论(0)
  • 2021-02-08 00:39

    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.

    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:

    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.

    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:

    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:

    exec 3<&0 </dev/null
    read -r var <&3
    
    0 讨论(0)
  • 2021-02-08 00:39

    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:

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

    or combined with spbnick's answer:

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

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

    0 讨论(0)
  • 2021-02-08 00:39

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

    perl -MFcntl -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) & ~O_NONBLOCK'
    
    0 讨论(0)
提交回复
热议问题