交互式 shell 可以变成非交互式 shell,反之亦然吗?

交互式 shell 可以变成非交互式 shell,反之亦然吗?

交互式 shell 可以变成非交互式 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.

从“-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.

第一句中的定义再次仅指开始一个贝壳的。

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

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


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

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

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

(虽然它也在 的 POSIX 定义中进行了定义sh,但该手册页 [ man 1p sh] 中“除非 shell 是交互式的”和类似语句的使用要少得多man bash,并且几乎完全专注于调用时间差异,因此我将重点关注 Bash从现在开始。)


shell“交互式”的一些含义只是相关的在调用时无论如何,例如 shell 在读取其他命令之前会获取哪些文件。然而,有任何时候都相关的含义(至少在 Bash 中)。因此,对于任何给定的情况,必须有一种方法来判断跑步shell,无论它是否是交互式的。

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

问题是:这实际上意味着 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.

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

(它出现这个问题的答案是“否”,手册页可以包含修饰符:“其标准输入和错误都连接到终端......在调用时,“但我不确定。)


如果答案是“不,shell 不能变得非交互式,反之亦然”,那么是什么确定的如何确定 shell 是否是交互式的?

换句话说:如果“交互式 shell”的行为在 后仍然存在set +i使用什么以确定这些行为应该继续适用?


免得有人怀疑:有交互式调用的 shell 的行为在 后持续存在set +i,非交互调用的 shell 的行为在 后持续存在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.

因此,通过取消设置该interactive_comments选项,我们可以看到交互式 shell 和非交互式 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

这证实了“交互式”和“具有”i的值$-不是相等的。

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


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

和,交互式 shell 可以变成非交互式 shell,反之亦然吗? (……通过改变这个特性?)

答案1

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

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

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

但如果您希望 shell 停止交互,您可以这样做:

. /some/file; exit

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

exec myshell /dev/tty

将当前的交互式 shell 替换为仍从 tty 设备读取命令的非交互式 shell。

请注意,对于 bash 4.4,set +i返回的结果与bash: set: +i: invalid option大多数其他 shell 中类似。

相关内容