zoukankan      html  css  js  c++  java
  • ubuntu下关于profile和bashrc中环境变量的理解

    (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) 其它

    echo $PATH # 查看环境变量PATH

    (6) 写在后面

    最后说一下,各个linux系统下的profile文件和bashrc文件都有所不同,我用的是ubuntu16.04,其它系统可能有所不同,可以自己看里面的shell代码进行理解和实践验证。

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

  • 相关阅读:
    钉钉outgoing机器人小项目开发
    js根据cookie判断,一天之内只弹出一次弹窗
    js倒计时功能
    jquery的$().each,$.each的区别
    VS代码提示自动高亮
    winform当前屏幕大小
    动态增删改控件
    datagridveiw样式
    sql 语句 提取中文的首字母
    按键监听及重写
  • 原文地址:https://www.cnblogs.com/liaohuiqiang/p/7197581.html
Copyright © 2011-2022 走看看