Wil*_*ard 17 shell bash shell-script terminology
注意:我对“交互式和非交互式之间有什么区别?”这个基本问题做了很多研究,我的研究结果让我提出了这个问题。
这个问题的序言很长,部分原因是我们对“交互式”使用什么类型的定义来回答它是至关重要的。定义可以是某个集合的任意标签;它可以描述各种属性;或者它可以为您提供可用于预测行为和理解目的的信息。 最后一种我们可以称之为“动作定义”或“动态定义”,它是最有用的。
在 中man 1p sh
,给出了交互式 shell 的以下定义:
Run Code Online (Sandbox Code Playgroud)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 手册页的措辞略有不同:
Run Code Online (Sandbox Code Playgroud)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的启动。
第二句话(在我的阅读中)定义了用作代理的条件,以确定 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' 出现在$-
:
Run Code Online (Sandbox Code Playgroud)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 是否为交互式的明确方法是什么?
换一种说法:如果有一个“交互式外壳”的行为在 之后持续存在set +i
,那么用什么来确定这些行为应该继续适用?
为了避免有人怀疑它:有是一个shell的行为交互调用后坚持set +i
和外壳的行为调用非交互这之后持续set -i
。例如,请考虑以下摘录man bash
:
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)
这证实了“interactive”和“has i
in the value $-
”是不等价的。
使用${parameter:?word}
未设置参数的类似测试会产生类似的结果,再次确认这$-
不是 shell 交互性的“真实来源”。
那么,最后,shell 的明确“交互性”特征存储在哪里?
而且,交互式 shell 是否可以变为非交互式,反之亦然? (...通过改变这个特性?)
我要问的问题是为什么有人想要这样做?
您可以禁用交互式 shell 的某些方面,例如:
PS1= PS2=
禁用提示set +m
禁用作业控制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 +i
以bash: set: +i: invalid option
类似的方式返回。