交互式 shell 是否可以变为非交互式,反之亦然?

Wil*_*ard 17 shell bash shell-script terminology

交互式 shell 是否可以变为非交互式,反之亦然?

注意:我对“交互式和非交互式之间有什么区别?”这个基本问题做了很多研究,我的研究结果让我提出了这个问题。

这个问题的序言很长,部分原因是我们对“交互式”使用什么类型的定义来回答它是至关重要的。定义可以是某个集合的任意标签;它可以描述各种属性;或者它可以为您提供可用于预测行为和理解目的的信息。 最后一种我们可以称之为“动作定义”或“动态定义”,它是最有用的。


在 中man 1p sh,给出了交互式 shell 的以下定义:

   If the -i option is present, or  if  there  are  no  operands  and  the
   shell’s  standard  input and standard error are attached to a terminal,
   the shell is considered to be interactive.
Run Code Online (Sandbox Code Playgroud)

从提到的“-i 选项”和“操作数”一词的使用来看,这是指 shell 的调用,而不是可以在运行的 shell 中检查的属性。

Bash 手册页的措辞略有不同:

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.   PS1 is set and $- includes i if bash is interactive, allowing
   a shell script or a startup file to test this state.
Run Code Online (Sandbox Code Playgroud)

第一句中的定义再次仅指shell的启动

第二句话(在我的阅读中)定义了用作代理的条件,以确定 shell 是否以定义为使其“交互式”的特定方式启动。

请注意,不会将这句话解释为:“当且仅当$-包含 'i' 时,bash shell 才是交互式的。” $-似乎只是一个方便的指标,而不是交互式的定义。这与我的问题至关重要。


这两个(POSIXsh定义和 Bash 定义)都是机械定义,它们说明在什么情况下“交互式”标签适用于您启动的 shell。它们不是动作定义,因为它们没有给出这个标签的任何含义

但是,我看到在 Bash 手册页的其余部分中,散布着对 shell 以某些方式运行的引用,“除非它是交互式 shell”或“仅在交互式 shell 中,或者如果设置了 _____ 选项”。(有很多例子,这不是这个问题的重点。)

因此,我承认“交互式”只是手册页其余部分描述的默认“交互式”行为(选项设置)集合的一个方便标签。它本身不是一个基本术语或对象;它在 shell 的源代码之外没有权威的定义。(不同于,例如,术语“打开文件描述符”或“停止的进程”指的是内核本身设计中内置的抽象。)

(虽然它也在 POSIX 定义中定义sh,但手册页 [ man 1p sh] 使用的“除非 shell 是交互式的”和类似语句的使用量远远少于使用man bash,并且几乎只关注调用时间差异,所以我将关注 Bash从现在开始。)


外壳“交互式”的一些含义无论如何只在调用时相关,例如外壳在读取其他命令之前获取哪些文件。但是,是在任何时间相关的影响(至少在击)。因此,对于任何给定的正在运行的shell,必须有一种方法来判断它是否是交互式的。

set +i在交互式 Bash shell 中运行会导致从$-.

问题是:这是否真的意味着 shell 不再具有交互性?

根据 Bash 的确切定义,它不应该,因为定义中没有任何地方要求'i' 出现在$-

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.
Run Code Online (Sandbox Code Playgroud)

对确切定义的严格解读也提出了一个问题:如果交互式终端的 stdin 或 stderr 被重定向,因此它们不再连接到终端,shell 是否变为非交互式?

似乎这个答案是“否”,手册页可能包含修饰符:“其标准输入和错误都连接到终端......在调用时, ”但我不知道肯定的。)


如果答案是“不,shell 不能变为非交互式,反之亦然”,那么确定 shell 是否为交互式明确方法是什么?

换一种说法:如果有一个“交互式外壳”的行为在 之后持续存在set +i那么用什么来确定这些行为应该继续适用?


为了避免有人怀疑它:有一个shell的行为交互调用后坚持set +i和外壳的行为调用非交互这之后持续set -i。例如,请考虑以下摘录man bash

COMMENTS
   In a non-interactive shell, or an interactive shell in which the inter-
   active_comments  option  to  the  shopt  builtin  is enabled (see SHELL
   BUILTIN COMMANDS below), a word beginning with # causes that  word  and
   all  remaining  characters  on that line to be ignored.  An interactive
   shell without the interactive_comments option enabled  does  not  allow
   comments.  The interactive_comments option is on by default in interac-
   tive shells.
Run Code Online (Sandbox Code Playgroud)

因此,通过取消设置该interactive_comments选项,我们可以看到交互式和非交互式 shell 之间的区别。以下脚本演示了这种差异的持久性:

#!/bin/bash

# When the testfile is run interactively,
# all three comments will produce an error
# (even the third where 'i' is not in '$-').
# When run noninteractively, NO comment will
# produce an error, though the second comment
# is run while 'i' IS in '$-'.

cat >testfile <<'EOF'
shopt interactive_comments
shopt -u interactive_comments
shopt interactive_comments
echo $-
#first test comment
set -i
echo $-
#second test comment
set +i
echo $-
#third test comment
EOF

echo 'running bash -i <testfile'
bash -i <testfile
echo 'running bash <testfile'
bash <testfile
Run Code Online (Sandbox Code Playgroud)

这证实了“interactive”和“has iin the value $-”是等价的。

使用${parameter:?word}未设置参数的类似测试会产生类似的结果,再次确认这$-不是 shell 交互性的“真实来源”。


那么,最后,shell 的明确“交互性”特征存储在哪里?

而且,交互式 shell 是否可以变为非交互式,反之亦然? (...通过改变这个特性?)

Sté*_*las 9

我要问的问题是为什么有人想要这样做?

您可以禁用交互式 shell 的某些方面,例如:

  • PS1= PS2= 禁用提示
  • set +m 禁用作业控制
  • 在某些 shell 中禁用历史记录
  • 您可以卸载zle并完成所有模块zsh

但是如果你想让 shell 停止交互,你可以这样做:

. /some/file; exit
Run Code Online (Sandbox Code Playgroud)

告诉它从中获取其余命令/some/file/dev/tty如果您仍然希望从 tty 设备读取命令,则替换为),尽管与非交互式 shell 仍然存在一些差异,例如行为return或事实它仍然会进行工作控制或:

exec myshell /dev/tty
Run Code Online (Sandbox Code Playgroud)

用一个仍然从 tty 设备读取命令的非交互式 shell 替换您当前的交互式 shell。

请注意,在 bash 4.4 中,在大多数其他 shell 中set +ibash: set: +i: invalid option类似的方式返回。

  • @Wildcard Dash 接受`set +i` 并停止显示提示。这是用户不应该做的事情,因此行为取决于外壳并且通常是偶然的而不是外壳实现者故意决定的结果也就不足为奇了。 (4认同)
  • @Wildcard,如果 shell 是作为“交互式”启动的,它仍然如此。您可以在较旧的 bash 版本中执行 `set +i` 这一事实是一个错误。 (2认同)