ubuntu下关于profile和bashrc中环境变量的理解,ubuntubashrc


(0) 写在前面

有些名词可能需要解释一下。(也可以先不看这一节,在后面看到有疑惑再上来看相关解释)

$PS1和交互式运行(running interactively): 简单地来说,交互式运行就是在终端上输入指令运行,非交互式运行就是执行sh文件。交互式运行的时候echo $PS1会输出一长串字符,非交互式运行echo $PS1会输出#或$,,$代表普通用户,#代表root。非交互式运行是不会执行bashrc文件的配置内容的,这点需要注意一下,因为平常都在终端上执行指令,很容易忽略这一点:在bashrc中配置的东西,在执行sh文件的时候就失效了。

启动bash shell:就是启动一个bash shell进程,通常可以理解为打开一个终端。需要注意的是如果你在终端输入sh后会发现自己又进入另一个shell命令行(注意这不是交互式运行,可以echo $PS1验证),这个时候其实fork了一个shell 子进程(会复制一份原终端shell进程的全局变量),如果你在这个shell命令行又输入了一次sh,那么相当于fork的shell子进程又fork了一个shell子进程,这个时候就启动了三个bash shell进程。

输入exit或者ctrl-d可以退出当前shell,这里需要连续exit两次才可以回到原来的终端shell进程(这个时候就变回一个shell进程了)。

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不为空),如果不是则给PS1赋’#‘或'$','#'代表root用户,'$'代表普通用户。如果是交互式运行还要是否启动了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代码进行理解和实践验证。

此次总结大致理顺了一下整个环境变量的“流通过程”,理解这个过程之后思路应该清晰了很多,如有错误,欢迎指正。

相关内容