1

我正在尝试设置一个 shell 脚本,该脚本screen仅在从交互式 shell 调用时才会启动会话(或重新加入现有会话)。我看到的解决方案是检查是否$-包含字母“i”:

#!/bin/sh -e

echo "Testing interactivity..."
echo 'Current value of $- = '"$-"
if [ `echo \$- | grep -qs i` ]; then
  echo interactive;
else
  echo noninteractive;
fi

但是,这会失败,因为脚本是由一个新的非交互式 shell 运行的,该 shell 作为#!/bin/sh顶部的结果调用。如果我获取脚本而不是运行它,它会按需要工作,但这是一个丑陋的 hack。我宁愿让它在我运行时工作。

那么如何测试脚本中的交互性呢?

4

6 回答 6

1

试一试,看看它是否符合您的要求:

#!/bin/sh
if [ $_ != $0 ]
then
  echo interactive;
else
  echo noninteractive;
fi

下划线 ( $_) 扩展为用于调用脚本的绝对路径名。零 ( $0) 扩展为脚本的名称。如果它们不同,则从交互式 shell 调用脚本。在 Bash 中,后续的扩展$_将扩展参数提供给前一个命令(将 的值保存$_在另一个变量中以保留它可能是个好主意)。

来自man bash

   0      Expands to the name of the shell or shell script.  This  is  set
          at shell initialization.  If bash is invoked with a file of com‐
          mands, $0 is set to the name of that file.  If bash  is  started
          with  the  -c option, then $0 is set to the first argument after
          the string to be executed, if one is present.  Otherwise, it  is
          set  to  the file name used to invoke bash, as given by argument
          zero.
   _      At shell startup, set to the absolute pathname  used  to  invoke
          the  shell or shell script being executed as passed in the envi‐
          ronment or argument list.  Subsequently,  expands  to  the  last
          argument  to the previous command, after expansion.  Also set to
          the full pathname used  to  invoke  each  command  executed  and
          placed in the environment exported to that command.  When check‐
          ing mail, this parameter holds the name of the  mail  file  cur‐
          rently being checked.
于 2010-07-12T23:42:17.737 回答
1

$_可能不适用于所有与 POSIX 兼容的 sh,尽管它可能适用于必须。

$PS1只有当 shell 是交互式的时才会设置。所以这应该工作:

if [ -z "$PS1" ]; then
    echo noninteractive
else
    echo interactive
fi
于 2010-07-22T13:19:35.533 回答
0

尝试tty

if tty 2>&1 |grep not ; then echo "Not a tty"; else echo "a tty"; fi

man tty :tty 实用程序将附加到标准输入的终端名称写入标准输出。写入的名称是 ttyname(3) 返回的字符串。如果标准输入不是终端,则写入消息“not a tty”。

于 2010-07-14T08:41:17.213 回答
0

简单的回答:不要在 ` ` 或[ ].

这里不需要这些构造中的任何一个。


显然我不能确定你的期望

[ `echo \$- | grep -qs i` ]

进行测试,但我不认为它正在测试你认为它正在测试的东西。

该代码将执行以下操作:

  • 在子shell 中运行echo \$- | grep -qs i(由于` `)。
  • 捕获子shell 的标准输出。
  • 用包含该输出的字符串替换原来的 ` ` 表达式。
  • 将该字符串作为参数传递给[命令或内置(取决于您的 shell)。
  • 仅当该字符串为非空时才生成成功的返回码[(假设该字符串看起来不像 的选项[)。

一些可能的问题:

  • -qs选项应该导致它grep不产生任何输出,所以我希望[测试一个空字符串,不管它是什么$-样子。
  • 反斜杠也有可能转义美元符号并导致将文字“美元减号”(而不是变量的内容)发送到grep.

另一方面,如果您删除了[和反引号,而是说

if echo "$-" | grep -qs i ; then

然后:

  • 您当前的外壳将扩展"$-"为您要测试的值,
  • echo ... |会将其发送到grep其标准输入,
  • grep当该输入包含字母时将返回成功的返回码i
  • grep由于-qs标志,将不打印任何输出,并且
  • if语句将使用grep' 的返回码来决定采用哪个分支。

还:

  • 没有反引号会用运行时产生的输出替换任何命令,并且
  • 没有[命令会尝试将 的返回码替换为grep它试图从grep.

有关如何使用该if命令的更多信息,请参阅优秀 BashGuide 的这一部分

于 2013-10-01T12:59:45.360 回答
0

您可以尝试使用类似...

if [[ -t 0 ]]
then
     echo "Interactive...say something!"
     read line
echo $line
else
     echo "Not Interactive"
fi

测试字段中的“-t”开关检查给定的文件描述符是否与终端匹配(例如,如果输出要打印到终端,您也可以这样做来停止程序)。在这里它检查程序的标准输入是否与终端匹配。

于 2010-07-15T20:02:25.117 回答
0

如果您想在$-不分叉外部进程(例如grep)的情况下测试 的值,那么您可以使用以下技术:

if [ "${-%i*}" != "$-" ]
then
    echo Interactive shell
else
    echo Not an interactive shell
fi

i*这会从 then 检查的值中删除任何匹配项,$-看看这是否有任何不同。


(该${parameter/from/to}构造(例如[ "${-//[!i]/}" = "i" ],当当且仅当互动时为真)可以在 Bash 脚本中使用,但在 Dash 中不存在,后者/bin/sh在 Debian 和 Ubuntu 系统上。)

于 2013-10-01T13:20:00.527 回答