1

本文首发于个人博客,原文链接为:https://www.panyanbin.com/art...

欢迎学习交流,转载请保留作者信息以及原文链接。

有些时候,我们需要在linux用户登录时执行我们自己编写的脚本,比如登录时给个友好的交互输出提示。为了实现该目的,我们有必要去了解一下linux在用户登录时执行内部shell的顺序,这样才能把自定义的脚本放到对应位置去执行。

如果暂时不想了解linux用户登录时的内置脚本执行顺序,只是想看配置操作,可以直接看第二段:自定义脚本执行配置操作。

linux用户登录内置脚本执行顺序

关于用户登录的时候执行shell脚本的顺序如下图所示:

shell 过程

注意:老潘的测试机器是CentOS操作系统,所以会执行~/.bash_profile,操作系统不同,其文件名字有所不同(~/.bash_profile~/.bash_login~/.profile) ,总体的逻辑执行基本不变。

以下简单大致说明一下过程。

/etc/profile

任何一个用户(包括root用户)在进行登录时,都会先检查全局文件/etc/profile,若此文件存在,则使用source.命令去执行文件。

为什么使用source命令?因为是刚登入linux系统,相关的bash命令还没注入到shell中,无法通过相应的bash执行脚本,只能使用内置命令去执行。

我们cat一下/etc/profile文件,以下仅把相关的信息展示出来,更多信息可以自行去看。

# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

...
...

for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then 
            . "$i"
        else
            . "$i" >/dev/null
        fi
    fi
done

...

查看注释内容的提示信息:

  • 这是一个系统范围环境和启动程序,用于登录设置函数和命令别名则放置在 /etc/bashrc文件中(比如设置ll别名命令代替ls -l
  • 不推荐修改当前文件的内容,如果需要修改自定义环境变量,最好的方式是在目录/etc/profile.d/下创建sh脚本文件,脚本的文件名可自定义,脚本内容主要是自定义环境变量。

在以上内容中,除了注释之外,老潘还特意贴了一段代码,不了解shell脚本语言也能看懂大概意思,主要就是遍历/etc/profile.d目录下的sh脚本文件,然后对有可读权限的脚本文件使用点(.)命令去执行脚本。

此时可以了解到该文件作用就是,在系统级上给所有用户定义一些环境变量,这些环境变量可以在用户登录后的shell中访问到。而且这些环境变量推荐在/etc/profile.d/目录下的任意脚本sh文件中定义。

创建好全局环境变量后,只需要重新登录shell即可访问到环境变量,若不想退出重登录而希望在当前登录的shell中使其环境变量生效,可以使用命令source命令让其生效。

source /etc/profile.d/xxx.sh

我们来看一下的/etc/profile.d目录下有哪些脚本:

image-20210710005604288

注:此目录下的脚本文件列表根据不同系统而不同,老潘的测试系统是centOS。

下一步,会注入bash命令到shell中,使得我们可以通过/bin/bash命令调用shell脚本。

~/.bash_profile

若你的系统不存在该文件,检查你的系统是否CentOS,若是你可以手动创建一个,若不是,检查其他的文件名(~/.bash_login~/.profile

接下来,Linux将去用户的家目录下找.bash_profile文件是否存在,若存在则同样使用source.命令去执行此文件。

root用户在/root/.bash_profile,其他用户在/home/用户/.bash_profile

此文件的作用是允许当前用户去自定义一些用户级的环境变量,在此文件中定义的环境变量(没有在/etc/profile中定义),其他用户访问不到。此外,还将调用用户的~/.bashrc文件。

以下为此文件的默认内容:

image-20210710005408092

当用户登录时,该文件仅仅执行一次。而且Linux执行完本文件程序后,就提示登录成功并进入到用户命令行交互。在当前登录的shell中,后面的脚本(~/.bashrc/etc/bashrc)被执行都是因为在此文件的脚本内容编写了调用那些脚本文件的代码。

~/.bashrc

~/.bashrc文件的作用主要是定义一些当前用户自定义的命令别名和函数。

文件在用户登录时在~/.bash_profile文件中进行调用,此外,当前用户每次打开新的shell时,此文件也被读取执行。

老潘在此提醒一下:千万不要在生产机器上随意去注释默认的代码,除非你知道代码被注释后的后果!!

以下输出老潘的测试机器上的~/.bashrc文件内容:

image-20210710014342077

可以看到,除了等于一些自定义命令别名之外,还有一个调用执行全局定义脚本文件/etc/bashrc,判断文件若是普通文件就执行。

/etc/bashrc

从上文知道/etc/bashrc文件是由~/.bashrc文件去调用,若注释执行代码行后,在用户登录时或打开新shell本文件不会被读取执行。

老潘在此再次提醒一下:千万不要在生产机器上随意去注释默认的代码,除非你知道代码被注释后的后果!!

文件的内容比较多,主要展示一下文件注释内容:

# /etc/bashrc

# System wide functions and aliases
# Environment stuff goes in /etc/profile

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

...

大概意思就是,此文件作用是定义系统级的函数和命令别名,但是若想新增全局性的自定义的函数和命令,不要修改本文件,而是写入到定义全局环境变量的那个自定义文件中/etc/profile.d/xxxx.sh

当然这个文件内容比较多,部分的作用在non-interactive-login shell调用时,执行/etc/profile.d/目录下定义的脚本,把相关定义全局性的环境变量、函数和命令注入到当前shell中。因为非交互式的登录shell没有读取和执行/etc/profile的步骤,只会读取执行~/.bashrc文件。该处作用知道一下即可,有兴趣可以去细剖,一般不需要过多关注。

执行顺序测试

1. 添加测试代码

为了测试各文件的执行顺序,我使用root用户登录服务器后做了以下的操作,因此~目录就是/root/目录:

  • /etc/profile.d/目录下创建一个test.sh文件,并在内部写入以下代码

    echo '/etc/profile.d/test.sh'
  • /root/.bash_profile文件的顶部和底部添加几行测试代码,其他代码不处理

    echo '/root/.bash_profile --start'
    
    # ...文件默认的内容
    
    echo '/root/.bash_profile --end'
  • /root/.bashrc文件顶部和底部同样添加几行测试代码,其他代码不处理

    echo '/root/.bashrc --start'
    
    # ...文件默认的内容
    
    echo '/root/.bashrc --end'
  • /etc/bashrc文件顶部和底部也添加几行测试代码,其他代码不处理

    echo '/etc/bashrc --start'
    
    # ...文件默认的内容
    
    echo '/etc/bashrc --end'

2. 验证测试

添加了以上的测试输出代码后,我们保险一点,直接新开一个标签使用进行登录,原来的root不退出防止操作错误导致登录失败。

使用root进行登录,登录成功后,将输出以下内容:

/etc/profile.d/test.sh
/root/.bash_profile --start
/root/.bashrc --start
/etc/bashrc --start
/etc/bashrc --end
/root/.bashrc --end
/root/.bash_profile --end

使用非root用户进行登录,登录成功后,将输出以下内容:

/etc/profile.d/test.sh
/etc/bashrc --start
/etc/bashrc --end

这是因为非root用户登录时执行的是~/.bash_profile而非/root/.bash_profile

自定义脚本执行配置操作

根据以上说明的,我们大致可以确定几种方案使用,以下以用户登录后打个招呼作为案例说明。

1. 所有用户登录时都执行脚本

进入/etc/profile.d目录:

cd /etc/profile.d

创建自定义脚本sh文件,文件名随便,比如,say-hello.sh

vim say-hello.sh

编写执行的自定义脚本内容

echo "Hello, $USER. Welcome to login."
$USER变量是在脚本中获取到的当前登录用户

一般不会在这个sh文件中编写过多逻辑代码,只会配置一些环境变量和业务脚本的执行,比如

# /etc/profile.d/say-hello.sh

echo "Hello, $USER. Welcome to login."

node /usr/local/xxx/xx.js

这样看起来比较清晰,核心实现的代码都在其他目录中存放着。

2. 特定用户登录时执行脚本

针对特定用户,可以在用户的~/.bashrc文件中添加自定义脚本的执行代码

创建我的say-hello.sh文件

# ~/say-hello.sh

echo "Hello, $USER. Welcome to login."

然后在~/.bashrc中调用文件

# ~/.bashrc

# ...

bash ./say-hello.sh

如果是多个特定用户,我们可以在每个需要执行脚本的用户的./bashrc文件中添加脚本执行命令,也可以在/etc/profile.d编写脚本,然后根据当前登录用户判断是否执行该脚本。

小结

配置文件有好几个,我们一般约定:

  • 定义全局性(所有用户都使用)的环境变量,可以在/etc/profile.d/的自定义sh脚本文件中定义
  • 执行全局性(所有用户都执行)的命令别名/脚本执行,可以在/etc/profile.d/的自定义sh脚本文件中调用
  • 定义或执行特定用户自定义的命令别名和脚本,可以在~/.bashrc文件中定义或执行
  • 定义特定用户自定义的环境变量,可以在~/.bash_profile(注意在不同操作系统,其文件名不同,可能是.bash_login.profile)定义

参考

linux的开/关机脚本执行顺序和自启动脚本实践

ulimit最详解


panyanbin
4 声望0 粉丝