shell交互式脚本脚本_UnixShell进阶之定制你的专属Shell环境
使⽤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
shell最简单脚本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!
参考资料
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论