第三十三章. 杂项

 

Nobody really knows what the Bourne shell's grammar is. Even examination of the source code is little help.

 Tom Duff

33.1. 交互式和非交互式的shells和脚本

交互式的shell在 tty终端从用户的输入中读取命令. 另一方面, shell能在启动时读取启动文件,显示一个提示符并默认激活作业控制. 用户能交互地使用shell.

运行脚本的shell一般都是非交互的shell. 但脚本仍然可以存取它拥有的终端. 脚本里甚至可以仿效成可交互的shell.
   1 #!/bin/bash
   2 MY_PROMPT='$ '
   3 while :
   4 do
   5   echo -n "$MY_PROMPT"
   6   read line
   7   eval "$line"
   8   done
   9 
  10 exit 0
  11 
  12 # 这个例子脚本, 和上面的解释由
  13 # Stéphane Chazelas 提供(再次感谢).

让我们考虑一个要求用户交互式输入的脚本,通常用read语句 (参考例子 11-3). 真正的情况可能有些混乱.以现在假设的情况来说,交互式脚本被限制在一个tty设备上,它本身已经是从一个控制终端或一个中被用户调用的.

初始化和启动脚本不必是非交互式的,因为它们必须不需要人为地干预地运行。许多管理和系统维护脚本也同样是非交互式的。不多变的重复性的任务可以自动地由非交互式脚本完成.

非交互式的脚本可以在后台运行,但交互脚本在后台运行则会被挂起,等待永远不会到达的输入。解决这个难点的办法可以写预料这种情况的脚本或是内嵌here document 的脚本来获取脚本期望的输入,这样就可作为后台任务运行了.在最简单的情况,重定向一个文件给一个read语句提供输入(read variable <file). 这就可能适应交互和非交互的工作环境下都能达成脚本运行的目的.

如果脚本需要测试当前是否运行在交互shell中,一个简单的办法是找一下是否有提示符变量,即$PS1是否设置了. (如果脚本需要用户输入数据,则脚本会显示一个提示符.)
   1 if [ -z $PS1 ] # 没有提示符?
   2 then
   3   # 非交互式
   4   ...
   5 else
   6   # 交互式
   7   ...
   8 fi
另一个办法是脚本可以测试是否在变量$-中出现了选项"i".
   1 case $- in
   2 *i*)    # 交互式 shell
   3 ;;
   4 *)      # 非交互式 shell
   5 ;;
   6 # (Courtesy of "UNIX F.A.Q.," 1993)

脚本可以使用-i选项强制在交互式模式下运行或脚本头用#!/bin/bash -i. 注意这样可能会引起脚本古怪的行为或当没有错误出现时也会显示错误信息.