2013macbookpro python集成开发环境_shell if 非


使用Unix系统一段时间之后,应该对~/.bashrc,~/.bash_profile这些环境配置文件不陌生,而这些配置文件也是Unix Shell的精髓所在,在一次conda的更新中,出现了一个不愉快的结果,使得我查阅了相关的资料,系统地了解了bash shell的环境配置过程,在此和大家分享一下。本文参考了网上很多博客的相关内容,向这些开源社区的斗士致敬。

1.shell的分类

1.1 交互式Shell和非交互式Shell

这个概念对于学过脚本语言的人来说,特别容易理解。以python为例,我们有两种方法玩python,第一种是直接打开终端,输入python然后回车,就进入到交互式的python;第一种是创建一个xxx.py文件,然后打开终端,输入python xxx.py,这就是非交互式的python。

对于shell来说,交互模式就是你打开终端,shell等待你输入,并且一旦你回车即提交输入的命令,shell执行你的命令;非交互模式就是你写一个shell脚本,例如xxx.sh,然后在终端执行这个脚本,这种情况,shell不与你进行交互,而是读取xxx.sh中存储的命令,并且执行它们,当它读到文件结尾的EOF,shell就终止了。

变量的继承问题(存在问题,待更新)

交互式登陆开始于输入账户密码然后login,结束于终端logout或者直接关闭终端。新打开终端并不会记得上次关闭的终端里给变量赋的值,并且按⬆️也无法追溯上个关闭终端的历史输入命令。而非交互式终端就会继承,比如你先打开一个

1.1.1交互式登陆(不继承上一个Shell的变量)

(1)直接通过终端输入账号密码登录,会打印登陆信息


Last login: Tue Mar 12 10:38:46 on ttys000
You have mail.
zhangshengxingdeMacBook-Air:~ sxzhang$


(2)使用su - UserName(注意有空格)


zhangshengxingdeMacBook-Air:~ sxzhang$ sh login1.sh
sxzhang@222.195.74.36's password: 
Last login: Tue Mar 12 19:50:55 2019 from 114.214.194.133
[sxzhang@lw_s ~]$ su - yuantao
密码:
[yuantao@lw_s sxzhang]$ echo $-
himBH
[yuantao@lw_s sxzhang]$ su sxzhang
密码:
[sxzhang@lw_s ~]$ echo $-
hB


Note:两种登录方式看似一样,但是echo $-的结果不一样,后面我们会提到,没有i的那种是非交互式的。

1.1.2非交互式登陆(会继承上一个shell的全部变量)

(1)su UserName

(2)执行脚本 (当我们执行脚本的时候.我们就已经进入到了一个子shell)

(3)交互式下,输入bash,进入一个子shell

1.2登录式Shell与非录陆式Shell

1.2.1登录式Shell

需要用户名、密码登录后才能进入的shell(或者通过--login”选项生成的shell,例如bash --login)。

1.2.2非登录式shell:

不需要输入用户名和密码即可打开的Shell,例如:直接命令“bash”就是打开一个新的非登录shell。

1.2.3区别

(1)执行exit命令,退出一个shell(登录或非登录shell);执行logout命令,退出登录shell(不能退出非登录shell)

(2)对于用户来说,登陆shell和非登陆shell的主要区别是:启动shell时所执行的startup文件不同。登陆shell执行startup文件为:/etc/profile、~/.bash_profile、~/.bashrc(这里只是从现象上得出的推论,这种推论是有问题的,稍后讨论),而非登陆shell执行的startup文件仅为:~/.bashrc。

(3)区分方式是echo $0,输出结果有短划线,是登录式:


Last login: Sun Mar 17 23:51:56 2019 from 114.214.252.93
[sxzhang@lw_s ~]$ echo $0
-bash
[sxzhang@lw_s ~]$ bash
[sxzhang@lw_s ~]$ echo $0
bash


2.配置文件

配置文件一般有两类六种,一种叫用户配置文件,放置在目录~/下:


~/.bash_profile、~/.bashrc、和~/.bash_logout


一种叫全局配置文件,存放在目录/etc下:


/etc/bashrc   /etc/profile  etc/logout


不同的Unix版本可能命名存在差别,但是关键字是一样的。~/.profile(由BourneShell和Korn Shell使用)和~/.login(由C Shell使用)两个文件是~/.bash_profile的同义词,目的是为了兼容其它Shell。在Debian中就使用~/.profile文件代 替~/.bash_profile文件。

这些文件是隐藏文件,直接输入ls指令是无法看到的,需要:


$ ls -ah /etc/


此外,并不是所有的电脑一开始都有这六种文件,可能只有其中几种,有必要的话,用户可以自己新建,但是名字必须符合规范。

2.1各种配置文件的作用时机

2.1.1用户配置文件

(1)~/.bash_profile在用户每次开启一个新的登录式Shell时被读取,里面所有的命令都会被bash执行。如果已经登录了Shell,并在这个Shell里用Vim或者其他方式修改了~/.bash_profile文件,这个时候,原有的Shell并不会立即执行这个新的文件,但是你可以:


source ~/.bash_profile


这样就相当于命令bash在此Shell重新执行一遍新文件里的所有命令。

当然你可以关掉旧的Shell,打开一个新的登录式Shell,这样新的~/.bash_profile会被bash执行一遍。这个道理可以推广到其他物种配置文件。

(2)~/.bashrc文件会在bash shell调用另一个bash shell时读取,也就是在shell中再键入bash命令启动一个新shell时就会去读该文件。例如,在shell里运行一个shell脚本,就相当于启动了一个新的shell,只不过这个shell在脚本运行完后就自动关闭了,于是,每当我们在shell里面运行一个shell脚本时,系统会先执行一遍~/.bashrc,再执行shell脚本。这样可有效分离登录和子shell所需的环境。但一般来说都会在~/.bash_profile里调用~/.bashrc脚本以便统一配置用户环境,这可以通过在~/.bash_profile添加如下命令实现:


if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi
#如果存在`~/.bashrc`文件就执行它


(3)~/.bash_logout在退出shell时被读取。所以我们可把一些清理工作的命令放到这文件中。例如我们在一个shell里面运行一个shell脚本:


$ sh 1.sh


系统在运行完这个脚本后,会接着运行一次~/.bash_logout

2.1.2全局配置文件

那么,一个很自然的问题来了,全局配置文件什么时候发挥作用呢?

(1)登录式shell(包括交互式登录shell和使用“–login”选项的非交互shell),它会首先读取和执行/etc/profile全局配置文件中的命令,然后依次查找~/.bash_profile~/.bash_login~/.profile这三个配置文件,读取和执行这三个中的第一个存在且可读的文件中命令。除非被“–noprofile”选项禁止了。 (2)非登录式shell里,一遍读取 ~/.bashrc (和 /etc/bashrc )文件,不同的发行版里面可能有所不同,如RHEL6.3中非登录shell仅执行了“~/.bashrc”文件(没有执行/etc/bashrc),而KUbuntu10.04中却依次执行了/etc/bash.bashrc 和 ~/.bashrc 文件。

2.2各种Shell运行时,配置文件的执行顺序

(1)登录式(不管是不是交互)

  • 登录:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile
  • 开启子shell: ~/.bashrc--> /etc/bashrc

(2)交互式非登录

/etc/bashrc--> ~/.bashrc--> /etc/profile.d/*.sh

(3)非交互式非登录Shell

打开一个终端,输入bash进入非登录式Shell,运行一个脚本,此时即非交互式非登录Shell,所以上面配置文件的都不会执行。但我们可以在脚本的最开始加上#!/bin/bash,让脚本用登录式Shell来解释执行,此时,变成了登录非交互式Shell,参见(1)。

3.设计自己的配置文件

3.1先读一份配置文件


#未完待续
#取别名
alias cp='cp -i'


4.遇到的问题

更新Conda后,我发现每次打开终端,画风都是这样的:


(base) zhangshengxingdeMacBook-Air:~ sxzhang$


没错,最前面多了(bash),后来我发现是conda修改了我的~/.bash_profile


(base) zhangshengxingdeMacBook-Air:~ sxzhang$ cat .bash_profile
# added by Anaconda3 5.3.1 installer
#>>> conda init >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$(CONDA_REPORT_ERRORS=false '/Users/sxzhang/anaconda3/bin/conda' shell.bash hook 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/Users/sxzhang/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/Users/sxzhang/anaconda3/etc/profile.d/conda.sh"
       CONDA_CHANGEPS1=false conda activate base 
    else
        export PATH="/Users/sxzhang/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
#<<< conda init <<<


所以,每次打开终端,系统执行一遍~/.bash_profile,会执行里面的:


conda activate base


我灵机一动,在这段话后面加了一句:


conda deactivate


于是,打开终端再也不会出现(base)了。

另一个遇到的问题,为什么在Linux,我们总是配置~/.bashrc但是在Mac下,我们配置就没有用呢,要去配置~/.bash_profile才行?哈!什么情况加载~/.bashrc,上面说得很清楚了,交互式非登录Shell,那在Mac下,你打开Term,echo一下$0,看看,前面是不是有个-号?说明这是交互式的登录Shell,当然不会加载~/.bashrc了。实属正常。你肯定要问了,为啥Linux下没问题呢?你打开~/.profile看看就知道了,这货竟然在~/.profile文件里面source了~/.bashrc