一个 交互式 shell 从用户的输入中读取命令,输入通过一个tty。除此之外,这样的 shell 在激活时会读取启动文件,显示提示符,并默认启用作业控制。用户可以与 shell 进行交互。
运行脚本的 shell 始终是非交互式的。尽管如此,脚本仍然可以访问其tty。甚至可以在脚本中模拟交互式 shell。
#!/bin/bash MY_PROMPT='$ ' while : do echo -n "$MY_PROMPT" read line eval "$line" done exit 0 # This example script, and much of the above explanation supplied by # St�phane Chazelas (thanks again). |
让我们将交互式脚本视为需要用户输入的脚本,通常通过 read 语句(参见示例 15-3)。“实际情况”实际上比这更复杂。目前,假设交互式脚本绑定到一个 tty,即用户从控制台或 xterm 调用的脚本。
Init 和启动脚本必然是非交互式的,因为它们必须在无人干预的情况下运行。许多管理和系统维护脚本同样是非交互式的。不变的重复性任务迫切需要通过非交互式脚本来实现自动化。
非交互式脚本可以在后台运行,但交互式脚本会挂起,等待永远不会到来的输入。通过使用 expect 脚本或嵌入式 here document 向作为后台作业运行的交互式脚本提供输入,可以解决这个难题。在最简单的情况下,重定向一个文件来为 read 语句提供输入(read variable <file)。这些特殊的方法使得通用脚本可以在交互式或非交互式模式下运行。
如果脚本需要测试它是否在交互式 shell 中运行,只需查找 prompt 变量,$PS1 是否已设置即可。(如果正在提示用户输入,则脚本需要显示提示符。)
if [ -z $PS1 ] # no prompt? ### if [ -v PS1 ] # On Bash 4.2+ ... then # non-interactive ... else # interactive ... fi |
或者,脚本可以测试 $- 标志中是否存在 "i" 选项。
case $- in *i*) # interactive shell ;; *) # non-interactive shell ;; # (Courtesy of "UNIX F.A.Q.," 1993) |
然而,John Lange 描述了一种替代方法,使用 -t test 操作符。
# Test for a terminal! fd=0 # stdin # As we recall, the -t test option checks whether the stdin, [ -t 0 ], #+ or stdout, [ -t 1 ], in a given script is running in a terminal. if [ -t "$fd" ] then echo interactive else echo non-interactive fi # But, as John points out: # if [ -t 0 ] works ... when you're logged in locally # but fails when you invoke the command remotely via ssh. # So for a true test you also have to test for a socket. if [[ -t "$fd" || -p /dev/stdin ]] then echo interactive else echo non-interactive fi |
![]() | 可以使用 -i 选项或#!/bin/bash -i头来强制脚本以交互模式运行。请注意,这可能会导致不稳定的脚本行为,甚至在没有错误时也显示错误消息。 |