交互式外壳能否变为非交互式,反之亦然?


16

交互式外壳能否变为非交互式,反之亦然?

注意:我已经对“交互式和非交互式之间的区别是什么?”这一基本问题进行了大量研究,研究的结果使我提出了这个问题。

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


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

   If the -i option is present, or  if  there  are  no  operands  and  the
   shells  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.

第一句话中的定义再次仅指壳的开始

第二句(在我读)定义用作条件的代理建立外壳是否在被定义为使其成为特定的方式开始“互动”。

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


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

但是,我看到在Bash手册页的其余部分中,都以某些方式对shell进行了混乱的引用,“除非是交互式shell,否则”或“仅在交互式shell中,或者设置了______选项”。(有很多示例,但这不是这个问题的重点。)

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

(尽管在的POSIX定义中也进行了定义sh,但手册页[ man 1p sh]的“除非外壳是交互式的”和类似的语句的用法要少得多man bash,并且几乎专门针对调用时间的差异,因此,我将重点讨论Bash从现在开始。)


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

set +i在交互式Bash shell中运行会导致从的内容中删除“ i” $-

问题是:这实际上意味着外壳不再是交互式的吗?

根据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.

严格阅读确切的定义还会引发一个问题:如果将交互式终端的stdin或stderr重定向到它们不再连接到终端的位置,那么外壳是否会变得非交互式?

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


如果回答是,“不,外壳不能成为非交互式的,反之亦然,”那么什么是明确的方法来确定是否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.

因此,通过取消设置该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

这证实了“互动”和“具有i的价值$-”是等价的。

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


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

而且,交互式外壳能否变为非交互式,反之亦然? (...通过更改此特征?)


聊天中也对此问题进行了详细讨论
通配符

Answers:


9

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

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

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

但是,如果您希望外壳不再是交互式的,则可以执行以下操作:

. /some/file; exit

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

exec myshell /dev/tty

要用非交互式外壳替换当前的交互式外壳,该外壳仍会从tty设备读取命令。

请注意,使用bash 4.4时,在其他大多数shell中都set +i返回一个bash: set: +i: invalid optionlike。


绝对同意这将是一件荒谬的事情 正如我提到的,我的“交互式”概念是,它只是默认行为的集合,这些行为在与shell 交互时很有用。如果您可以分别更改每个行为,并且确实要更改每个行为,那么问题“它是否仍是交互式外壳?” 只是荒谬的语义;这甚至不是一个重要的问题。 但是....
通配符

1
@Wildcard,如果您exec < <(sleep infinity)在交互式外壳中进行操作,则您将获得一个交互式程度不是很高的交互式外壳。Shell仍然会认为自己是交互式的,因为它$-仍然包含i,但您可能不会。我不确定还有更多要讨论的问题。
斯特凡Chazelas

2
@Wildcard,如果外壳程序以开头interactive,则保持不变。您可以set +i在较旧的bash版本中进行操作的事实是一个错误。
斯特凡Chazelas

1
@Wildcard,如果您查看的源代码bash,则可能会发现存在一个interactive全局布尔变量,该变量映射到的i标志$-。更改该布尔值不会自动更改交互式Shell的所有行为。不支持从交互式更改为非交互式。
斯特凡Chazelas

4
@Wildcard Dash接受set +i并停止显示提示。这是用户不应该做的事情,因此,行为取决于shell是很奇怪的,并且常常是偶然的,而不是shell实现者有意决定的结果。
吉尔斯(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.