linux - .bash_profile .bash_rc 什么区别
大家讲道理
大家讲道理 2017-04-17 11:06:23
0
5
852

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

大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

全部回覆(5)
阿神

幾個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中的變量,他們是"父子"關係.

巴扎黑

其實這個問題的核心就是 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.

小葫芦

原文見 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}文件先被載入

大家讲道理

~/.bash_profile 隻在當前用戶登入的時候加載,~/.bashrc 在每次 Bash 初始化的時候都會加載。

阿神

經常看到 .bash_profile 裏的內容是

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

有時候我也搞不清其中的關係,不過我一般都是把啟動配置放在.bashrc下麵,如果不管用的話,再創建上述.bash_profile。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板