您现在的位置是:首页 > 正文

什么是交互式登录 Shell

2024-01-30 20:10:45阅读 1

今天在看~/.bashrc文件的时候看到一行,对它的意思不是非常了解:

[[ $- != *i* ]] && return

就特意上Google搜索了一下,对于搜索关键字是符号(这里是$-)的,我是不怎么抱希望的。所以干脆将$-的结果(himBh)放到Google一起搜索。果然找到两篇不错的帖子:

这两个帖子都是在ChinaUnix论坛上的。这些老论坛虽然人气不行,但是一些资源还是很赞的,这些总结帖都非常好。尤其是第一篇非常值得一读,我只是看了其中一部分。对sh和bash的区别并没有仔细看,觉得这些没必要去死记,到时候碰到问题再去理解就好,要不然就太枯燥了。

Linux用了这么多年,Shell一直在用,执行命令,安装软件,配置文件,以及编写脚本,但是说真地,我对Shell一直不是非常了解,几乎没看过和它相关的任务手册和文档。一般系统中最常见的Shell还是Bash。Bash的手册非常长,我是坚决不看的,头痛。后果就是对Bash的一些现象一知半解,其实这些基本上在手册上都是有写的。

回到正文,在~/.bashrc中开头的话意思是,如果$-的内容不包含i,则直接退出脚本。加一句题外话,return语句只能用于函数或者被source的脚本中返回,如果直接执行则会报错。事实上,$-中包含i意思是指当前的Shell是一个交互式(interactive)的Shell。什么是交互式的呢?就像我们平时通过命令行做事一样,你敲一个命令,终端解析执行完之后给你一个结果,这样一种交互式的形式。那么,平时我们接触的Shell基本上都是交互式的,如gnome-terminal打开一个Shell以及通过Ctrl+alt+1等切换过去的文本终端。交互式Shell下, "echo $-"返回的字符串中包含i,否则不包含。也可以通过在bash后面加-i参数打开一个交互式的Shell,具体可以看man bash。bash后面加-c参数执行命令打开的是非交互式Shell,可以用以下命令验证:

$ bash -c 'echo $-'  # 返回hBc

解释完交互式之后,继续解析文章题目后半部分中的登录二字。登录Shell其实很好理解,就是我们平时通过用户名/密码才能登录的Shell,最典型的就是用Ctrl+alt+1切换过去的文本终端。如何区分登录Shell和非登录Shell呢,可以通过查看$0的值,登录Shell返回-bash,而非登录Shell返回的是bash。平时gnome-terminal打开的Shell就是非登录Shell。也可以通过在bash后面加--login参数打开一个登录Shell。虽然是这么说,但我还是不知道如何在gnome-terminal下打开一个登录式的Shell。

接下来看看这些不类的调用Shell有什么区别,可以查看man bash中的Invocation一节。一段一段来看:

A login shell is one whose first character of argument zero is a -, or one started with the --login option.
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是否为交互式的。

When bash is invoked as an interactive login shell, or as a non-inter‐active shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior. When a login shell exits, bash reads and executes commands from the file ~/.bash_logout, if it exists.

如果一个Shell是交互式登录Shell或者使用--login参数的非交互式登录Shell。这首先会读取/etc/profile文件并执行,如果该文件存在。然后按顺序查找~/.bash_profile, ~/.bash_login,或者~/.profile,读入第一个存在的文件并执行。可能通过指定--noprofile参数来禁止这种默认行为。当登录Shell退出之后,会读取~/.bash_logout文件并执行。

When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists. This may be inhibited by using the --norc option. The --rcfile file option will force bash to read and execute commands from file instead of ~/.bashrc.

如果是一个交互式非登录Shell,bash会读取~/.bashrc文件中定义的命令。同时,可以指定--norc参数来禁止该行为,或者通过--rcfile指定其它文件。

When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the filename.

如果是一个非交互式非登录Shell,比如运行一个Shell脚本,它会查找BASH_ENV定义的文件读入并执行。

后面其实还有一段说sh和bash不同的之处的一段话,这里就不放了,其中读入这些以上文件的时候不考虑bash开头的那几个文件,做到尽量少的设置,保证与POSIX标准兼容。

事实上,在ArchLinux下,登录Shell也是会读入~/.bashrc文件的,因为~/.bash_profile文件的内容默认是这样的:

#
# ~/.bash_profile
#

[[ -f ~/.bashrc ]] && . ~/.bashrc

同时,在$HOME目录下同时存在~/.bash_profile和~/.profile两个文件,并且两个文件都会被读入,因为我的fcitx配置就是放在~/.profile中的。这与man bash里面的描述有些不一致。可能桌面环境下会有一些区别吧,又或者是用GDM登录的缘故?然后我顺着这条线索去找/etc/gdm下面的配置文件,果然在/etc/gdm/Xsession中发现以下内容:

# First read /etc/profile and .profile
test -f /etc/profile && . /etc/profile
test -f "$HOME/.profile" && . "$HOME/.profile"
# Second read /etc/xprofile and .xprofile for X specific setup
test -f /etc/xprofile && . /etc/xprofile
test -f "$HOME/.xprofile" && . "$HOME/.xprofile"

一切都有好解释了。好了,不再继续写下去了,Dota去!

网站文章

  • orcale的to_number方法

    orcale的to_number方法

    TO_NUMBER函数()是Oracle中常用的类型转换函数之一,主要是将字符串转换为数值型的格式,与TO_CHAR()函数的作用正好相反。To_number函数的格式如下:To_number(var...

    2024-01-30 20:10:38
  • JS 转换HTML转义符

    JS转换HTML转义符//去掉html标签123functionremoveHtmlTab(tab) {returntab.replace(/<[^<>]+?>/g,'');//删除所有HTML标签}//普通字符转换成转意符12...

    2024-01-30 20:10:31
  • vs2008中在解决方案资源管理器查看当前打开文件

    vs2008中在解决方案资源管理器查看当前打开文件

    2019独角兽企业重金招聘Python工程师标准&gt;&gt;&gt; ...

    2024-01-30 20:10:23
  • 后台LocalDateTime参数的接收问题(Failed to convert value of type ‘java.lang.String‘ to required type ‘java.tim

    后台LocalDateTime参数的接收问题(Failed to convert value of type ‘java.lang.String‘ to required type ‘java.tim

    后台LocalDateTime参数的接收问题(Failed to convert value of type ‘java.lang.String’ to required type ‘java.tim...

    2024-01-30 20:09:53
  • NLP词向量发展历程

    NLP词向量发展历程

    这篇文章记录词向量的发展历程,包括tf-idf、word2vec、GloVe、ELMo、OpenAI GPT以及Bert,只记录个人认为比较核心的内容,以及一些值得思考的边角细节。1、tf-idftf...

    2024-01-30 20:09:35
  • Java类的继承

    Java类的继承

    Java类的继承

    2024-01-30 20:09:17
  • php中加载更多,php – 在Javascript中加载更多功能

    基本思想是监听滚动事件,并在服务器端实现分页.只要文档或包含的HTML元素滚动,就会触发滚动事件.我将使用此草图作为参考,记住以下事项:假设浏览器窗口的高度为800px,内容的初始高度为2500px....

    2024-01-30 20:08:47
  • ES6 操作数组 方法 区别 map filter reduce find 热门推荐

    1. mapmap函数可以看成是一种映射函数,而且是一一映射array.map(function(参数){....函数体......})es6写法:array.map((参数)=&gt;{....函数...

    2024-01-30 20:08:41
  • 架构-vue拖拽平台

    5)右边属性配置内容来自editor-config.jsx文件中props和model,编辑好的属性传到editor-block.jsx文件的render(即editor-config.jsx文件中r...

    2024-01-30 20:08:34
  • react创建组件的两种方式

    1. 使用构造函数来创建组件如果需要传参,在函数中加一个props参数来接受,并且必须向外return一个合法的jsx创建的虚拟DOM。//1. 组件名首字母为大写 2. 必须return 合法的jsx// 这里就可以相当于子组件function Hellow (props){ //props为父组件传过来的数据 //如果打印props的话,只要子组件用的到东西都会打印出来,在这里...

    2024-01-30 20:08:05