如何检查外壳是否登录/交互/批处理


143

我想我了解交互式,登录和批处理Shell之间的区别。请参阅以下链接以获取更多帮助:

我的问题是,如果我处于交互式,登录名或批处理shell中,如何使用命令/条件进行测试?

我正在寻找命令或条件(返回truefalse),并且也可以将其放在if语句上。例如:

if [[ condition ]]
   echo "This is a login shell"
fi

3
还有另一个问题:STDIN和/或STDOUT是否连接到tty(终端)或管道(文件或进程)?如以下一些评论所述,这是一个相关但独特的测试。
马克·哈德森

Answers:


160

我假设使用的是bash外壳或类似外壳,因为标签中没有列出外壳。

要检查您是否处于交互式外壳中:

[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'

要检查您是否在登录shell中:

shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'

通过“批处理”,我假设您的意思是“非交互式”,因此对交互式外壳程序的检查就足够了。


12
对于zsh用户,可以使用以下方法检查登录外壳:if [[ -o login ]] ...
chb 2013年

1
如果您想知道“用户”相对于“ cron”是否运行了程序。[[TERM == “哑”]] &&回声“运行在cron。
埃里克Aronesty

10
@ErikAronesty并非所有的哑终端都是cron会话。
克里斯·

2
“我假设是bash shell或类似的东西,因为标签中没有列出shell。” –此语句的逻辑确实很漂亮!:)
Michael Le BarbierGrünewald2015年

2
@antonio那是因为您的引用是错误的,$-正在当前shell中进行扩展。如果在整个表达式周围使用单引号,则会得到正确的结果:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
克里斯·

33

在任何Bourne样式的shell中,该i选项指示shell是否是交互式的:

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This is a script";;
esac

没有可移植且完全可靠的方法来测试登录外壳。Ksh和zsh添加l到中$-。Bash设置login_shell选项,您可以使用进行查询shopt -q login_shell。可移植地,测试是否$0-:开头的shell通常知道它们是登录shell,因为调用者-在参数0(通常是可执行文件的名称或路径)上添加了前缀。这无法检测到特定于shell的调用登录shell的方式(例如ash -l)。


(...),因为呼叫者 –我认为此片段中缺少某些内容。
Piotr Dobrogost

如果$0始终以-任何方式开始,那将是理想的选择。但是至少有一个例外:对于bash,这并不总是正确的,即使它应该是登录shell。在您的框中尝试一下:调用bash --login,然后$0仍然显示bash
Wirawan Purwanto

@WirawanPurwanto我不确定我是否理解您的评论。那不是我在最后一句话中写的吗?
吉尔斯2015年

@吉尔斯:你是对的。对不起,我错过了你的最后一句话。
Wirawan Purwanto

24

鱼壳

fish如果其他用户偶然发现此页面,这是答案。

if status --is-interactive
    # ...
end

if status --is-login
    # ...
end

echo "darn, I really wanted to have to use globs or at least a case statement"

Fish文档:初始化


1
-1用于不必要的编辑。
尼克·巴斯汀

6
如果有人对@NickBastin的评论感到惊讶,他的观点很合理,所以我进行了编辑。原来的贪睡已经减少了一半。
2015年

18

csh / tcsh

对于cshtcsh我的.cshrc文件中包含以下内容:

if($?prompt) then               # Only interactive shells set $prompt
    ...
endif

专门针对tcshloginsh为登录shell设置了变量:

if($?loginsh) then              # A login shell..
    ...
endif

tcsh还有一个变量shlvl,该变量设置为嵌套shell的数量,其中登录shell的值为1。)


2
PS1无法测试交互式外壳。它几乎总是以交互方式设置,但是您可以取消设置。通常将其设置在非交互式外壳中,因为许多系统附带export PSin /etc/profile
吉尔斯(Gilles)

@Gilles感谢您的更正和编辑
Andrew Stein

17

另一种方法是检查结果 tty

if [ "`tty`" != "not a tty" ]; then

10
...或用于[ -t 0 ]测试STDIN是否为tty。您还可以根据需要使用1(STDOUT)或2(STDERR)。
derobert

@derobert-感谢您向我展示一些新东西
Adrian Cornish

10
这是一个不同的测试。可能有一个非交互式外壳,其输入是终端(无论何时在终端中运行脚本!),并且有可能(尽管很少)有一个交互式外壳而不是从终端获取输入。
吉尔斯

@Gilles如果外壳是交互式的,并且关闭并留下一个孩子disown并且还活着,那么tty最好知道它不再是交互式的,并且$-没有变化;我仍然对最佳方法感到困惑。
水瓶座力量

5
@AquariusPower然后,您要测试的不是交互式外壳,而是标准输入是否为终端。使用[ -t 0 ]。PS在我先前的评论中,我写道“存在很强的相关性”,我忘记了“除了以#!/bin/sh或类似字符开头的脚本的极为常见的情况”,该脚本是非交互式的,但可以连接到终端。
吉尔斯2014年

8

UNIX / Linux具有检查您是否在终端上的命令。

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi

1
dash也适用。
肯·夏普

7

您可以检查stdin是否为终端:

if [ -t 0 ]
then
    echo "Hit enter"
    read ans
fi


1

i不是要寻找的正确选项。-i就是要迫使原本非交互式的外壳变得交互式。正确的自动启用选项是-s,但是遗憾的是Bash无法正确处理。

您需要检查是否$-包含s(被允许自动激活)或包含i(不被允许自动激活,但仅与-i外壳程序的命令行选项耦合)。


1
s如果shell从stdin读取命令,而不是它是否是交互式的。交互式外壳程序不一定从stdin读取命令(try zsh -i < /dev/null,尽管zsh在这里似乎是例外)。Shell可能正在从stdin读取命令,并且不是交互式的(如sh < fileecho 'echo "$1"' | sh -s foo bar)。
斯特凡Chazelas

2
我想指出的是,即使是旨在进行交互的,原始的Bourne Shell也没有在$-中包含“ i”。
2015年

可以,但是在U&L上,“外壳”往往是指现代外壳。Bourne shell通常被认为是一种传统,并且您自己的变体还没有成为主流,不足以期望人们知道您在说什么,除非您明确指出。提到的问题[[...]]意味着ksh / bash / zsh。作为历史记录,您有一点要注意,在Bourne shell中无法进行检i$-。但随后检查s也无法可靠地进行。您还需要检查[ -t 0 ]i; 即使如此,这会是在角落里的情况一样上当echo 'exec < /dev/tty; that-check' | sh'
斯特凡Chazelas

最初的Bourne Shell附带Solaris直至Solaris 10,甚至在门槛上都包含aprox。自SVr4以来,shell中已知存在10个错误。因此,在Bourne Shell上添加提示并不是像您可能相信的那样。另一端的zsh兼容性不足,例如,当您尝试使用zsh运行“配置”时,它会失败,因此请注意将/ bin / sh设置为指向zsh。顺便说一句:我的Bourne Shell在默认情况下会设置-i以防万一。
2015年

3
我注意到POSIX似乎不需要$-包含i(它似乎需要s),我将在奥斯汀集团ML上提出这个问题。
斯特凡Chazelas
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.