environment-variables
  • interactive
  • sh
  • subshell
  • 2010-07-12 97 views 1 likes 
    1

    我想设置一个shell脚本,只有从交互式shell中调用会话才会启动screen会话(或重新加入现有会话)。我所看到的解决方案是检查是否$-包含字母“i”:如何从shell脚本中判断调用它的shell是否是交互式shell?

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

    然而,这种失败,因为脚本是由一种新的非交互shell中运行,调用在顶部的#!/bin/sh的结果。如果我编写脚本而不是运行脚本,它可以按照需要运行,但这是一个丑陋的黑客。当我运行它时,我宁愿让它工作。

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

    +0

    我只是想做点出来你的shebang说“sh”,但你的问题说“bash”。如果你期望在你的脚本中使用Bash特性,你应该将你的shebang设置为'#!/ bin/bash'(即使在你的系统中'sh'被符号链接到'bash')。 – 2010-07-14 13:18:54

    回答

    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. 
    
    +0

    这似乎在bash,dash和zsh中正常工作。谨慎解释魔术? – 2010-07-13 07:30:23

    +0

    @Ryan:我认为它也适用于ksh。我会用一些文档编辑我的答案。 – 2010-07-13 13:38:42

    +0

    请注意,如果在脚本的开头使用$ _,它将只能以这种方式工作。 – Harvey 2013-06-13 02:27:38

    0

    尝试tty

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

    人TTY: 的TTY实用程序写入安装于标准 输入到标准输出端子的名称。写入的名称是由ttyname(3)返回的字符串 。如果标准输入不是终端,则会写入 消息“not a tty”。

    0

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

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

    的“-t”开关在测试现场检查,如果给定的文件描述符匹配的终端(你也可以这样做是为了阻止该程序如果例如,输出将被打印到终端)。在这里它检查程序的标准是否与终端匹配。

    1

    $_可能不适用于每个POSIX兼容sh,尽管它可能适用于必须。

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

    if [ -z "$PS1" ]; then 
        echo noninteractive 
    else 
        echo interactive 
    fi 
    
    +1

    不应该是'-n“$ PS1”'? – 2010-08-06 20:52:59

    +0

    @Ryan很好,你说得对。我换了then/else代替。 – schot 2010-08-07 09:54:47

    +0

    唉,对于所有shell而言,**不是真的**:至少在Debian和Ubuntu系统中,''dash''设置'PS1',不管它是否是交互式的。 'printf'#!/ bin/sh \ necho“$ PS1”\ n'> check.sh; chmod + x check.sh; 。/ check.sh'在这个Ubuntu 12.04系统上输出'$'。 – 2013-10-01 11:35:21

    0

    答案很简单:不运行里面``或[ ]这些命令。

    这里没有必要使用这些构造。


    很明显,我不能肯定你所期望

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

    要测试,但我不认为这是检测一下你认为这是测试。

    该代码将执行以下操作:

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

    一些可能出现的问题:

    • -qs选项grep应使其不产生输出,所以我预计[,而无论什么$-看起来像测试一个空字符串。
    • 也可能是反斜杠转义美元符号并导致文字'美元减'(而不是变量的内容)发送到grep

    在另一方面,如果你删除的[和反引号,而是说

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

    则:

    • 当前shell将扩大"$-"你想要的值测试,
    • echo ... |将发送到grep的标准输入,
    • grep会返回一个成功的返回码时输入包含字母i
    • grep将打印无输出,由于-qs标志和
    • if声明将使用grep'返回代码来决定采用哪个分支。

    另外:

    • 没有反引号将替换的时候被运行产生输出的任何命令,
    • 没有[命令将尝试用一些返回代码,以取代grep的返回码它试图从grep产生的输出中自行重建。

    更多关于如何使用if命令,看到优秀的BashGuide的this section

    0

    如果你想测试的$-值而不分叉一个外部进程(例如grep),则可以使用以下技术:

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

    这将删除任何匹配i*$-然后检查值看看这是否有所作为。


    (该${parameter/from/to}结构(如[ "${-//[!i]/}" = "i" ]是当且仅当互动true)可以在Bash脚本中使用,但没有出现在短跑,这是/bin/sh在Debian和Ubuntu系统。)

    相关问题