linux - .bash_profile .bash_rc 什么区别

 Life一切安好 发布于 2022-11-06 17:38

以前公司的Linux貌似写.bash_profile是不管用的,所以一些alias和PS1都是写在bashrc里
现在自己的电脑反过来了,bashrc不管用,要写bash_profile
这两个文件到底有什么区别?是不是有哪里可以配置,让用户登陆的时候去加载某个文件的?

5 个回答
  • 经常看到 .bash_profile 里的内容是

    if [ -e ~/.bashrc ]; then
        source ~/.bashrc
    fi

    有时候我也搞不清其中的关系,不过我一般都是把启动配置放在.bashrc下面,如果不管用的话,再创建上述.bash_profile。

    2022-11-12 01:48 回答
  • ~/.bash_profile 只在当前用户登入的时候加载,~/.bashrc 在每次 Bash 初始化的时候都会加载。

    2022-11-12 01:48 回答
  • 原文见 https://gist.github.com/1564928

    Shell的不同分类

    根据启动Bash Shell的方式不同,对Shell有两种分类方式

    =

    登录Shell与非登录Shell

    =

    根据Shell的启动方式不同,可以将Shell分为

    1. Login Shell
    2. Non-login Shell

    Login Shell的定义是,当前shell的argv[0]的第一个字符是-,或当前shell使用了-l ( --login ) 选项。

    只要满足以上的两个条件的任意一个,bash就会表现得Login Shell一样。例如,以下列出的场景下,bash都是login shell:

    1. 执行bash -l -c 'w' ( 使用了-l选项 )
    2. 执行su -l admin ( 运行的Shell的argv[0]第一个字符是- )
    3. 执行login -f ( 运行的Shell的argv[0]第一个字符是- )
    4. 将当前目录加入到$PATH,根据以下命令创建到bash的链接并执行 ( 运行的Shell的argv[0]第一个字符是- )

    export PATH=".:$PATH"
    ln -s -- $(which bash) -bash   
    -bash

    =

    交互与非交互Shell

    =

    同时,根据Shell启动参数的不同,还可以将Shell分为

    1. Interactive Shell
    2. Non-interactive Shell

    Interactive Shell的定义很明确:$-环境变量中包含字符i的Shell就是Interactive Shell

    以下场景中,bash属于Interactive Shell

    1. bash执行时没有加上非选项参数 [^noa]
    2. bash执行时没有加上-c选项
    3. bash执行时,加上了-i选项

    以下场景中,bash属于Non-interactive Shell

    1. 使用rsync -e ssh同步文件(-c选项)
    2. 其他基于ssh的文件传输,如git、svn等(基本都启用了-c选项)

    不同Shell中启动时执行的文件

    Bash启动时会按照一定的顺序载入rc文件,定义PS1JAVA_HOME等环境变量,执行特定的脚本等。

    按照两种Shell分类排列组合,一共有4种组合。各个组合下启动载入rc文件的顺序和数量有区别,以下分别列出:

    =

    登录/非交互Shell & 登录/交互Shell

    =

    bash会依次执行以下文件

    1. /etc/profile [^sysconfdir]
    2. ~/.bash_profile
    3. ~/.bash_login
    4. ~/.profile

    =

    非登录/非交互Shell

    =

    执行$BASH_ENV环境变量中指定的脚本

    =

    非登录/交互Shell

    =

    1. “全局”bashrc(编译时定义SYS_BASHRC,默认为/etc/bash.bashrc
    2. ~/.bashrc [^exception_bashrc]

    SSH远程登录服务器执行命令场景分析

    上面在分析交互/非交互、登录/非登录Shell的时候,特地省略了ssh到远程服务器执行命令这种场景下Shell类型的分类,放在这里分析。

    相关的资料不是很多,不管是bash(1)还是ssh(1)还是sshd(1),都没有对这个场景详细说明过。经过多次尝试,在不同的rc文件里echo特定字符串,得出结论。如果分析有问题,请大家纠正。

    使用的命令为ssh 127.0.0.1 w进行分析,会发现这个命令执行时会载入~/.bashrc,不会载入/etc/profile等文件

    ~/.bashrc文件中放置命令ps -p $$ -o args=,可获得载入~/.bashrc文件的进程命令行为bash -c w,是一个非登录、非交互Shell。根据bash(1)INVOCATION段的说明,此时应该只载入$BASH_ENV环境变量的脚本,不会载入/etc/bash.bashrc~/.bashrc脚本

    进一步研究OpenSSH源码和Bash源码。OpenSSH中执行shell部分的代码如下:

    // from session.c of OpenSSH 5.9p1 
    /*
     * Execute the command using the users shell.  This uses the -c
     * option to execute the command.  
     */
    argv[0] = (char *) shell0;
    argv[1] = "-c";
    argv[2] = (char *) command;
    argv[3] = NULL;
    execve(shell, argv, env);
    perror(shell);
    exit(1);

    而Bash中的相关代码:

    // from config-top.h
    
    /* Define this if you want bash to try to check whether it's being run by
       sshd and source the .bashrc if so (like the rshd behavior). */
    /* #define SSH_SOURCE_BASHRC */
    
    // from shell.c of Bash 4.2
    
    #ifdef SSH_SOURCE_BASHRC
          run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) ||
                       (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0);
    #else
    
    /* ... */
    
    /* If we were run by sshd or we think we were run by rshd, execute
    ~/.bashrc if we are a top-level shell. */
    if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
    {
    #ifdef SYS_BASHRC
    #  if defined (__OPENNT)
        maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
    #  else
        maybe_execute_file (SYS_BASHRC, 1);
    #  endif
    #endif
        maybe_execute_file (bashrc_file, 1);
        return;
    }

    可以看到,只要编译前在config-top.h中定义SSH_SOURCE_BASHRC,那么尽管Bash在被sshd fork出来的时候加上了-c选项,也确实是non-login non-interactive shell,只要发现SSH_CLIENT或者SSH2_CLIENT环境变量存在,就仍然会依次载入SYS_BASHRC~/.bashrc文件。

    这个结论非常重要,因为包括svn、git、rsync在内很多命令都使用ssh作为传输层。如果/etc/bash.bashrc~/.bashrc文件配置不合理,这些命令的执行都会有问题。

    请注意,在此问题上,各发行版自带bash的行为可能不同。Debian 5和6的补丁都设置了SSH_SOURCE_BASHRC,用户自己编译时可能未设定,因此也不能简单地认为通过ssh执行命令时服务器上的bash一定载入bashrc系列文件,更不可依赖bashrc来执行初始化命令。

    常见问题分析

    =

    Banner、Motd类提示信息应该放在哪里?

    =

    某些服务器可以在用户登录时加入一些提示信息,提示用户操作等。这样的信息仅需要在用户登录时显示,因此可以将此类信息放在login shell才会载入的文件中,如/etc/profile~/.bash_profile~/.bash_login~/.profile

    是否能将此类提示信息放在~/.bashrc文件内呢?下面说明

    =

    ~/.bashrc文件是否能source ~/.bash_profile呢?

    =

    以前遇到过一个问题。跳板机上在~/.bashrc里显示了一些banner信息,导致诡异地无法从其他服务器rsync文件到这台跳板机上。

    rsync(1)DIAGNOSTICS部分可以看到,rsync非常依赖于shell执行时没有任何输出。如果在~/.bashrc中source了~/.bash_profile,而~/.bash_profile中又有无关的文字输出,就会导致从其他服务器rsync到此服务器失败,报错信息为"protocol version mismatch — is your shell clean?"。这也回答了上一节的问题:*banner类信息不能放在~/.bashrc文件内*

    但是反过来,在~/.bash_profilesource ~/.bashrc是可以的,但是使用时要非常小心(容易引起循环引用,导致问题)

    =

    ssh到服务器执行java -version为什么版本和实际应用使用的不一致?

    =

    目前JAVA_HOMEPATH等环境变量的定义是在/etc/profile。ASA比较常见的操作是脚本跑一个集群,ssh到相应服务器上确认java版本是否正确。这个时候shell只会载入~/.bashrc,不会载入/etc/profile

    解决方法可以用以下任一:

    1. source /etc/profile再执行java -version来判断
    2. 执行 ssh remote-host 'bash -l -c "java -version"'

    [^noa]: Non-option Arguments,即不以-开头的参数。例如,bash -l test.sh-l是option argument,test.sh是non-option argument
    [^sysconfdir]: 严格地说,是${SYSCONFDIR}/profile文件。${SYSCONFDIR}是程序编译时,传递给configure脚本的--sysconfdir选项指定的目录。编译时没有指定--sysconfdir则使用--prefix指定的路径下etc文件夹。默认${SYSCONFDIR}/
    [^exception_bashrc]: 存在例外情况。如果编译bash时加上了#define SYS_BASHRC /etc/bashrcCPPFLAGS加上了-DSYS_BASHRC=/etc/bashrc,那么任何时候~/.bashrc被载入前,${SYS_BASHRC}文件先被载入

    2022-11-12 01:48 回答
  • 其实这个问题的核心就是 Shell 初始化时读取配置文件的步骤,而 Shell 又可以分为两类:Login Shell 和 Non-login Shell。参考博客 Execution sequence for .bash_profile,...:

    1. Login Shell 初始化时配置文件读取顺序的伪代码示意:

    execute /etc/profile
    
    IF ~/.bash_profile exists THEN
        execute ~/.bash_profile
    ELSE
        IF ~/.bash_login exist THEN
            execute ~/.bash_login
        ELSE
            IF ~/.profile exist THEN
                execute ~/.profile
            END IF
        END IF
    END IF

    2. Non-Login Shell 初始化时配置文件读取顺序的伪代码示意:

    execute /etc/bash.bashrc
    IF ~/.bashrc exists THEN
        execute ~/.bashrc
    END IF

    最后,Mac 的终端默认开启为 Login Shell。而 Ubuntu 的 Gnome Terminal 默认开启的是 Non-Login Shell.

    2022-11-12 01:48 回答
  • 几个bash配置文件的说明:

    /etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行.并从/etc/profile.d目录的配置文件中搜集shell的设置.
    /etc/bashrc:为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取.
    ~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件.
    ~/.bashrc:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取.
    ~/.bash_logout:当每次退出系统(退出bash shell)时,执行该文件.

    另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是"父子"关系.

    2022-11-12 01:48 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有