Skip to content

Instantly share code, notes, and snippets.

@spacexnasa
Forked from yegle/bash-invocation.md
Created July 31, 2022 06:01
Show Gist options
  • Select an option

  • Save spacexnasa/925c082b64d5e6a9c380ad7b7d92f9ca to your computer and use it in GitHub Desktop.

Select an option

Save spacexnasa/925c082b64d5e6a9c380ad7b7d92f9ca to your computer and use it in GitHub Desktop.

Revisions

  1. @yegle yegle revised this gist Jan 5, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -163,5 +163,5 @@ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)


    [^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}``/`
    `[^sysconfdir]`: 严格地说,是`${SYSCONFDIR}/profile`文件。`${SYSCONFDIR}`是程序编译时,传递给`configure`脚本的`--sysconfdir`选项指定的目录。编译时没有指定`--sysconfdir`则使用`--prefix`指定的路径下`etc`文件夹。默认`${SYSCONFDIR}``/`
    [^exception_bashrc]: 存在例外情况。如果编译bash时加上了`#define SYS_BASHRC /etc/bashrc``CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入
  2. @yegle yegle revised this gist Jan 5, 2012. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@ Bash启动时会按照一定的顺序载入rc文件,定义`PS1`、`JAVA_HOME`

    bash会依次执行以下文件

    1. `/etc/profile` [^sysconfdir]
    1. `/etc/profile` `[^sysconfdir]`
    2. `~/.bash_profile`
    3. `~/.bash_login`
    4. `~/.profile`
    @@ -164,4 +164,4 @@ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)

    [^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/bashrc``CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入
    [^exception_bashrc]: 存在例外情况。如果编译bash时加上了`#define SYS_BASHRC /etc/bashrc``CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入
  3. @yegle yegle revised this gist Jan 5, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@ Bash启动时会按照一定的顺序载入rc文件,定义`PS1`、`JAVA_HOME`

    bash会依次执行以下文件

    1. `/etc/profile` [^sysconfdir]
    1. `/etc/profile` `[^sysconfdir]`
    2. `~/.bash_profile`
    3. `~/.bash_login`
    4. `~/.profile`
  4. @keliot keliot revised this gist Jan 5, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -67,7 +67,7 @@ bash会依次执行以下文件

    ### 非登录/交互Shell

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

    ## SSH远程登录服务器执行命令场景分析
  5. @keliot keliot revised this gist Jan 5, 2012. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -67,8 +67,8 @@ bash会依次执行以下文件

    ### 非登录/交互Shell

    执行`SYS_BASHRC`(编译时定义,默认为`/etc/bash.bashrc`
    执行`~/.bashrc`文件 [^exception_bashrc]
    1. `SYS_BASHRC`(编译时定义,默认为`/etc/bash.bashrc`
    2. `~/.bashrc` [^exception_bashrc]

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

  6. @keliot keliot revised this gist Jan 5, 2012. 1 changed file with 22 additions and 5 deletions.
    27 changes: 22 additions & 5 deletions bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -67,7 +67,8 @@ bash会依次执行以下文件

    ### 非登录/交互Shell

    仅会执行`~/.bashrc`文件 [^exception_bashrc]
    执行`SYS_BASHRC`(编译时定义,默认为`/etc/bash.bashrc`
    执行`~/.bashrc`文件 [^exception_bashrc]

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

    @@ -77,7 +78,7 @@ bash会依次执行以下文件

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

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

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

    @@ -99,7 +100,21 @@ exit(1);
    而Bash中的相关代码:
    ```c
    // 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)
    @@ -116,9 +131,11 @@ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
    }
    ```

    可以看到,Bash在被sshd fork出来的时候加上了`-c`选项,确实是non-login non-interactive shell,但是仍然会载入`~/.bashrc`文件。
    可以看到,只要编译前在`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`文件配置不合理,这些命令的执行都会有问题。

    这个结论非常重要,因为包括svn、git、rsync在内很多命令都使用ssh作为传输层。如果`~/.bashrc`文件配置不合理,这些命令的执行都会有问题
    请注意,在此问题上,各发行版自带bash的行为可能不同。Debian 5和6的补丁都设置了`SSH_SOURCE_BASHRC`,用户自己编译时可能未设定,因此也不能简单地认为通过ssh执行命令时服务器上的bash一定载入bashrc系列文件,更不可依赖bashrc来执行初始化命令

    ## 常见问题分析

    @@ -147,4 +164,4 @@ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)

    [^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/bashrc``CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入
    [^exception_bashrc]: 存在例外情况。如果编译bash时加上了`#define SYS_BASHRC /etc/bashrc``CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入
  7. @yegle yegle revised this gist Jan 5, 2012. 1 changed file with 7 additions and 4 deletions.
    11 changes: 7 additions & 4 deletions bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -19,9 +19,12 @@ Login Shell的定义是,当前shell的`argv[0]`的第一个字符是`-`,或
    2. 执行`su -l admin` ( 运行的Shell的`argv[0]`第一个字符是`-` )
    3. 执行`login -f` ( 运行的Shell的`argv[0]`第一个字符是`-` )
    4. 将当前目录加入到`$PATH`,根据以下命令创建到bash的链接并执行 ( 运行的Shell的`argv[0]`第一个字符是`-` )
    :::bash export PATH=".:$PATH"
    ln -s -- $(which bash) -bash
    -bash

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

    ### 交互与非交互Shell

    @@ -126,7 +129,7 @@ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)

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

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

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

  8. @yegle yegle revised this gist Jan 5, 2012. 1 changed file with 31 additions and 31 deletions.
    62 changes: 31 additions & 31 deletions bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -78,40 +78,40 @@ bash会依次执行以下文件

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

    ```c
    // 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);
    ```
    ```c
    // 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中的相关代码:
    ```c
    // from shell.c of Bash 4.2
    /* 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;
    }
    ```
    ```c
    // from shell.c of Bash 4.2
    /* 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;
    }
    ```

    可以看到,Bash在被sshd fork出来的时候加上了`-c`选项,确实是non-login non-interactive shell,但是仍然会载入`~/.bashrc`文件。

  9. @yegle yegle revised this gist Jan 5, 2012. 1 changed file with 11 additions and 8 deletions.
    19 changes: 11 additions & 8 deletions bash-invocation.md
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,18 @@
    # Bash Shell启动方式与rc脚本

    [TOC]
    ## Shell的不同分类

    ***

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

    ### 登录Shell与非登录Shell

    根据Shell的启动方式不同,可以将Shell分为
    1. Login Shell2. Non-login 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选项 )
    @@ -77,7 +78,7 @@ bash会依次执行以下文件

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

    :::c
    ```c
    // from session.c of OpenSSH 5.9p1
    /*
    * Execute the command using the users shell. This uses the -c
    @@ -90,10 +91,11 @@ bash会依次执行以下文件
    execve(shell, argv, env);
    perror(shell);
    exit(1);
    ```

    而Bash中的相关代码:

    :::c
    ```c
    // from shell.c of Bash 4.2
    /* If we were run by sshd or we think we were run by rshd, execute
    ~/.bashrc if we are a top-level shell. */
    @@ -109,6 +111,7 @@ bash会依次执行以下文件
    maybe_execute_file (bashrc_file, 1);
    return;
    }
    ```

    可以看到,Bash在被sshd fork出来的时候加上了`-c`选项,确实是non-login non-interactive shell,但是仍然会载入`~/.bashrc`文件。

    @@ -141,4 +144,4 @@ SA组内部以前遇到过一个问题。跳板机上在`~/.bashrc`里显示了

    [^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/bashrc``CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入
    [^exception_bashrc]: 存在例外情况。如果编译bash时加上了`#define SYS_BASHRC /etc/bashrc``CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入
  10. @invalid-email-address Anonymous renamed this gist Jan 5, 2012. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  11. @invalid-email-address Anonymous created this gist Jan 5, 2012.
    144 changes: 144 additions & 0 deletions bash-invocation
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,144 @@
    # Bash Shell启动方式与rc脚本

    [TOC]

    ***

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

    ### 登录Shell与非登录Shell

    根据Shell的启动方式不同,可以将Shell分为
    1. Login Shell2. 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]`第一个字符是`-` )
    :::bash 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文件,定义`PS1`、`JAVA_HOME`等环境变量,执行特定的脚本等。

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

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

    bash会依次执行以下文件

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

    ### 非登录/非交互Shell

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

    ### 非登录/交互Shell

    仅会执行`~/.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`环境变量的脚本,不会载入`~/.bashrc`脚本

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

    :::c
    // 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中的相关代码:

    :::c
    // from shell.c of Bash 4.2
    /* 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;
    }

    可以看到,Bash在被sshd fork出来的时候加上了`-c`选项,确实是non-login non-interactive shell,但是仍然会载入`~/.bashrc`文件。

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

    ## 常见问题分析

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

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

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

    SA组内部以前遇到过一个问题。跳板机上在`~/.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_profile`中`source ~/.bashrc`是可以的,但是使用时要非常小心(容易引起循环引用,导致问题)

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

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

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

    * 先`source /etc/profile`再执行`java -version`来判断
    * 执行 `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/bashrc`或`CPPFLAGS`加上了`-DSYS_BASHRC=/etc/bashrc`,那么任何时候`~/.bashrc`被载入前,`${SYS_BASHRC}`文件先被载入