(0) 写在前面
有些名词可能需要解释一下。(也可以先不看这一节,在后面看到有疑惑再上来看相关解释)
启动bash shell:就是启动一个bash shell进程,通常可以理解为打开一个终端。需要注意的是如果你在终端输入sh后会发现自己又进入另一个交互式界面,这个时候其实fork了一个shell 子进程,如果你在这个交互式界面又输入了一次sh,那么相当于fork的shell子进程又fork了一个shell子进程,这个时候就启动了三个bash shell进程。
输入exit或者ctrl-d可以退出当前shell,这里需要连续exit两次才可以回到原来的终端shell进程(这个时候就变回一个shell进程了)。
$PS1和交互式运行(running interactively): 简单地来说,交互式运行就是在终端上输入指令运行,非交互式运行就是执行sh文件。交互式运行的时候$PS1是有值的。非交互式运行是不会执行bashrc文件的配置内容的,这点需要注意一下,因为平常都在终端上执行指令,很容易忽略这一点:在bashrc中配置的东西,在执行sh文件的时候就失效了。
source profile或source bashrc:source一个sh文件,就是把sh文件的内容加载到本shell环境中执行。可以理解为:执行sh是非交互式运行;在终端source sh文件,相当于在终端执行sh文件的指令,就是交互式运行了。(后面这一句暂且作为推测,因为还没做实验验证,回头验证一波)
(1) profile和bashrc
配置环境变量一般在这两种文件中。先讲讲什么时候执行,后面再介绍这两种文件做了什么。
profile在系统登录后执行,只在登录系统时执行一次,包括针对系统的/etc/profile和针对用户的~/.profile。
bashrc在每次启动bash shell(打开终端或者在终端输入sh)后执行,包括针对系统的/etc/bash.bashrc和针对用户的~/.bashrc(这里注意一下我的ubuntu里是/etc/bash.bashrc,其它系统可能是/etc/bashrc)
cat /etc/profile cat /etc/bash.bashrc cat ~/.profile cat ~/.bashrc
(2) 环境变量
因为要配置环境变量,所以要对环境变量有所了解。shell中的环境变量分为全局变量和局部变量。
blogger="piligrimHui" 这样定义的为局部变量 export blogger="pilgrimHui" 这样定义的为全局变量(export这个变量,则升级为全局变量)
2.1 局部变量:父进程定义的局部变量,子进程无法访问;子进程定义的局部变量,父进程无法访问。
# parent.sh #!/bin/bash pid="parent" sh child.sh echo "父shell访问子shell的cid:$cid"
# child.sh #!/bin/bash echo "子shell访问父shell的pid:$pid" cid="child"
sh parent.sh 子shell访问父shell的pid: 父shell访问子shell的cid:
2.2 全局变量:父shell定义的全局变量,子shell自身会复制一份父shell的全局变量,所以子shell对全局变量的操作不影响父shell的全局变量。子shell定义的全局变量,父shell不可用。
# parent.sh #!/bin/bash export name="parent" echo "父shell的name:$name" sh child.sh echo "子shell修改name之后,父shell的name:$name" echo "父shell访问子shell定义的nickName:$nickName"
# child.sh #!/bin/bash echo "子shell的name:$name" name="child" echo "子shell修改name后,子shell的name:$name" nickName="baby"
sh parent.sh 父shell的name:parent 子shell的name:parent 子shell修改name后,子shell的name:child 子shell修改name之后,父shell的name:parent 父shell访问子shell定义的nickName:
(3) profile做了什么
登录shell随着用户的登录而启动,可以看作是第一个shell,后续的shell都是登录shell的子shell。
登录shell会执行针对系统的/etc/profile和针对用户的~/.profile。为了让环境变量在后续的所有shell都能访问到,可以在这里配置全局的环境变量,但是注意profile只会在登录的时候执行一次,所以一般配置完后需要重新登录才能生效。(虽然可以自行source profile但是只在当前shell进程有效,这里的shell进程可以理解为在一个终端里,但是如果在终端里输入sh其实相当于开了两个shell进程,一个父进程一个子进程)
对于/etc/profile,首先会检查是否交互式运行(即$PS1不为空),是否启动了bash shell,如果是则执行/etc/bash.bashrc对bash进行相关配置。然后会执行/etc/profile.d目录下的shell文件,有一些作为自启动程序,有些用来定义一些全局环境变量。
对于~/.profile,首先检查是否启动了bash shell,如果是则执行~/.bashrc对bash进行相关配置。然后重新设置了PATH(所以导致不同用户的环境变量PATH不一样)。
# /etc/profile: system-wide .profile file for the Bourne shell (sh(1)) # and Bourne compatible shells (bash(1), ksh(1), ash(1), ...). if [ "$PS1" ]; then if [ "$BASH" ] && [ "$BASH" != "/bin/sh" ]; then # The file bash.bashrc already sets the default PS1. # PS1=‘\h:\w\$ ‘ if [ -f /etc/bash.bashrc ]; then . /etc/bash.bashrc fi else if [ "`id -u`" -eq 0 ]; then PS1=‘# ‘ else PS1=‘$ ‘ fi fi fi if [ -d /etc/profile.d ]; then for i in /etc/profile.d/*.sh; do if [ -r $i ]; then . $i fi done unset i fi
# ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login # exists. # see /usr/share/doc/bash/examples/startup-files for examples. # the files are located in the bash-doc package. # the default umask is set in /etc/profile; for setting the umask # for ssh logins, install and configure the libpam-umask package. #umask 022 # if running bash if [ -n "$BASH_VERSION" ]; then # include .bashrc if it exists if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi fi # set PATH so it includes user‘s private bin directories PATH="$HOME/bin:$HOME/.local/bin:$PATH"
(4) bashrc做了什么
当启动bash shell(打开终端)的时候会执行/etc/bash.bashrc和~/.bashrc。
在执行/etc/profile和~/.profile时如果检查到bash shell执行的话(对于/etc/profile还要先检查是否交互式运行),也会执行这两个文件。
我们来看看这两个bashrc做了什么
对于/etc/bash.bashrc:首先检查是否交互式运行,不是就什么都不做。是的话,后面是一堆乱七八糟的操作。
对于~/.bashrc:首先检查是否交互式运行,不是就什么都不做。是的话,后面一堆乱七八糟的操作,其中有一些别名操作,我们平常用的ll就是在这里设置了,是ls -alF的别名。
因为每次启动shell进程这里都会执行,所以一般也可以在这后面配置环境变量。
最常见的配置方法是vim ~/.bashrc然后在最后几行加上环境变量的配置,然后source ~/.bashrc或者重启终端即可。
# System-wide .bashrc file for interactive bash(1) shells. # To enable the settings / commands in this file for login shells as well, # this file has to be sourced in /etc/profile. # If not running interactively, don‘t do anything [ -z "$PS1" ] && return ...
# ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples # If not running interactively, don‘t do anything case $- in *i*) ;; *) return;; esac ... # some more ls aliases alias ll=‘ls -alF‘ alias la=‘ls -A‘ alias l=‘ls -CF‘
(5) 写在后面
最后说一下,各个linux系统下的profile文件和bashrc文件都有所不同,我用的是ubuntu16.04,其它系统可能有所不同,可以自己看里面的shell代码进行理解和实践验证。
此次总结大致理顺了一下整个环境变量的“流通过程”,理解这个过程之后思路应该清晰了很多,如有错误,欢迎指正。