4

我正在开发一个不需要与用户交互的脚本,如果我的脚本中的程序需要用户输入某些内容,那么脚本应该会失败并立即退出。

我已经关闭了STDIN脚本顶部的 ,这适用于某些命令,但有些命令需要在另一个文件描述符中输入(通常是那些要求输入密码的命令,例如gitor sudo)。

目前我的脚本是:

#!/bin/bash

# close STDIN
exec 0<&-

# test that $1 exists and it is a valid folder containing a git repository
# ...

cd "$1"

git fetch
# if git is not correctly configured, it asks for a password and
# my script waits for it :(

那么,我该如何避免这种情况呢?

注意:我不是在问如何在gitor sudoor中进行无密码配置whatever,而是要防止bash(or sh) 中的程序期望用户输入并在这种情况下立即失败。

4

3 回答 3

3

首先让我说,我认为这不是解决您的问题的正确方法。完全没有。必须有一个更好的特定于应用程序的解决方案,你真的应该找到它。

主要问题是,如果不知道要“强制关闭”哪些程序,您将不知道如何使它们“出错”。如果您确实了解这些程序,CodeGnome 的解决方案似乎很好。

另请注意,并非所有程序都直接从 STDIN 读取输入。例如,Python 的 getpass 模块直接打开一个附加文件描述符到/dev/tty,因此关闭或重定向 STDIN 无关紧要。这也是sudo接受密码的方式,我相信这也是 ncurses 的工作方式。以这种方式阅读可以让您在不显示在屏幕上的情况下获得密码。

对于不直接从/dev/tty(例如 bash's )读取的提示,只需从(例如)read重定向 STDIN可能会让您到达某个地方。或者,您可以做您正在做的事情并关闭 STDIN,但是当程序遇到关闭的 STDIN 或仅包含 EOF 的重定向的 STDIN 时,程序的行为方式是您无法控制的。 希望程序会如您所愿出错,但也许它会继续循环,期待有效的输入。谁知道?/dev/null./prompt.sh </dev/null

此外,无论是关闭还是重定向都不会是全局的工作方式,如果有的话。某些程序可能会退出,因为您希望关闭 STDIN,其他程序可能需要来自的 EOF/dev/null

因此,执行此操作的方法不是通用的、包罗万象的解决方案,而是针对您放置在该位置的程序量身定制的解决方案。更好的是,不要使用try(运行程序),然后catch (程序要求输入的情况)方法,只需以您知道它们不会要求输入的方式调用程序。

无论如何,话虽如此,一种可能可行的方法是关闭 STDIN 并将进程置于后台。例如:

#!/bin/bash

exec 0<&-
./prompt.sh &

或者,将 STDIN 重定向到 /dev/null 并将进程置于后台。例如:

#!/bin/bash

./prompt.sh </dev/null &

然后,您需要检查程序的返回码(带有$?)以查看它们是否正确退出。(希望您正在使用的未知程序列表遵循标准返回值方案)

STDIN 的关闭/重定向将处理 STDIN 用于接受输入的情况,而后台进程将处理 is 的情况/dev/tty(因为后台进程没有 tty)。

如果程序提示您使用其他方法(直接打开一个 FD 到您的伪终端,弹出一个图形输入框,为您提供声音提示等),您就只能靠自己了。

于 2012-06-26T11:34:38.080 回答
2

与其尝试关闭标准输入或标准错误,不如使用一个简短的期望脚本,如果它看到密码提示就会退出。例如:

#!/bin/bash

cd "$1"

expect -c '
    log_user 0
    spawn git fetch
    expect -timeout 30 -re "ass(phrase|word)" { exit 1 }
    '

# Do something based on the exit status of the expect script.
[[ $? -eq 1 ]] && { echo 'Password prompt detected!' >&2; exit 1; }

如果看到密码或密钥密码提示,expect 脚本将返回退出状态 1。然后 bash 脚本可以自由地做同样的事情,或者采取其他行动。

希望有帮助!

于 2012-06-26T09:57:32.153 回答
0

大多数(全部?)*NIX 都有一个tty命令,该命令打印出 shell 的名称,如果 shell 连接了 tty,则tty退出0,否则退出1错误。

if ! tty>&/dev/null; then echo "Not a terminal; goodbye."; exit 1; fi
于 2012-06-28T18:11:05.360 回答