免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: FH
打印 上一主题 下一主题

关于 bash 模拟 sh 时针对环境变量的讨论 [复制链接]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
1 [报告]
发表于 2007-01-09 15:28 |显示全部楼层
原帖由 FH 于 2007-1-2 08:33 发表
当bash以sh为名运行时,在交互非login模式下,其继承了所有环境变量(包括任何用户定义的变量),唯独不继承PS*!
号称是靠向POSIX,但是俺用过的所有Unix(AIX、HPUX、SCO)的sh,在该模式下都是继承PS*变量的。 ...


不知道 FH 所定義的“交互非login模式”跟我們所理解的是否一致的?還是有特定所指?
如下是 man bash 的內容:
       A login shell is one whose first character of argument zero is a -,  or
       one started with the --login option.

       An  interactive  shell  is one started without non-option arguments and
       without the -c option whose standard input and error are both connected
       to  terminals  (as determined by isatty(3)), or one started with the -i
       option.  PS1 is set and $- includes i if bash is interactive,  allowing
       a shell script or a startup file to test this state.


由此看來,只要完成 login 只後,在 command line 輸入 bash 或 sh 都應該是“交互非login模式”囉。
上面有提到 PS1 會被設定,我猜,這裡的設定應該是會被“重設”。而兄的問題在於 PS1 是否會從 parent shell 繼承下來吧? 如果我猜得對,那你看到的現象是正常的。

再看 man:
        When  an  interactive  shell that is not a login shell is started, bash
       reads and executes commands from ~/.bashrc, if that file exists.   This
       may  be inhibited by using the --norc option.  The --rcfile file option
       will force bash to read and  execute  commands  from  file  instead  of
       ~/.bashrc.

所以,除了從 parent 的 env/export 所繼承外,~/.bashrc 也是會影響環境結果的。
但不同的 linux distro 都會去修改 /etc/skel/.bashrc 的內容,
這時,最好請兄台說一下你目前试用的版本,還有 ~/.bashrc 的實際代碼才好分析。

有些版本,會從 ~/.bashrc 去 source /etc/bashrc,然後再去 source /etc/profile.d/*.sh 。
而有些則不一定會。
而 FH 兄前面的所謂解決方法,就是在 /etc/profile.d/*.sh 裡去執行,那是可以的。

不過,上面是用 bash 做 command ,如果換成 sh 的話:
       If bash is invoked with the name sh, it  tries  to  mimic  the  startup
       behavior  of  historical  versions  of sh as closely as possible, while
       conforming to the POSIX standard as well.  When invoked as an  interac‐\r
       tive  login  shell, or a non-interactive shell with the --login option,
       it first attempts to read and execute commands  from  /etc/profile  and
       ~/.profile,  in  that  order.   The  --noprofile  option may be used to
       inhibit this behavior.  When invoked as an interactive shell  with  the
       name  sh,  bash  looks for the variable ENV, expands its value if it is
       defined, and uses the expanded value as the name of a file to read  and
       execute.  Since a shell invoked as sh does not attempt to read and exe‐\r
       cute commands from any other startup files, the --rcfile option has  no
       effect.   A  non-interactive  shell  invoked  with the name sh does not
       attempt to read any other startup files.   When  invoked  as  sh,  bash
       enters posix mode after the startup files are read.

       When  bash  is  started in posix mode, as with the --posix command line
       option, it follows the POSIX standard for startup files.  In this mode,
       interactive  shells  expand  the ENV variable and commands are read and
       executed from the file whose name is  the  expanded  value.   No  other
       startup files are read.

所以看來是有 $ENV 這個變數來決定要執行的 script。
如果 ENV 沒設定,那就不執行了。
以我的 openSuSE10.2(GNU bash, version 3.1.17(1)-release )為例,
ENV 是設為 /etc/bash.bashrc 。裡面有多行關於 PS1 的設定,因此也會影響實際的 prompt 結果。

結論就是:不同的發行版本,可能得到的結果都不盡相同,只能以實際的 initial script 作參考。

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2007-01-10 02:50 |显示全部楼层
不妨讓我們做做實驗,來進一步釐清問題所在。

如下是版本資訊:
kenny@x40:~> bash --version
GNU bash, version 3.1.17(1)-release (i586-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

實驗一:如下是針對 bash 的測試:
kenny@x40:~> echo "$PS1"
$(ppwd \l)\u@\h:\w>                         #這裡是原 PS1 值
kenny@x40:~> echo $ENV
/etc/bash.bashrc                        #這是原 $ENV 路經
kenny@x40:~> PS1="xxx: "        #修改 PS1,但沒有輸出為 env var
xxx: bash                                        #進入 bash
kenny@x40:~> exit                        #prompt 被 reset 了,看來是被 .bashrc 修改了
exit                                                #退出
xxx: bash --norc                                #再次進入 bash,但使用了 --norc 選項
bash-3.1$ exit                                # 結果 prompt 設為 bash 的 default 值
exit                                                #退出
xxx: export PS1                                #將 PS1 輸出為 env var
xxx: bash                                        #進入 bash
kenny@x40:~> exit                        #似乎 export 前後沒產生變化
exit                                                #退出
xxx: bash --norc                                #使用 --norc
xxx: exit                                        #注意!這次不是 default 值,
                                                        #而是跟 parent 一致,這說明了 env var 是可以繼承的
exit                                                #退出

實驗二:為了還原環境,開一個新的 bash sehll 來測試 sh :
kenny@x40:~> echo "$PS1"
$(ppwd \l)\u@\h:\w>                         #原設 PS1 定值
kenny@x40:~> echo $ENV
/etc/bash.bashrc                        #這是原 $ENV 路經
kenny@x40:~> PS1="xxx: "        #修改 PS1,但沒有輸出
xxx: sh                                                #進入 sh
kenny@x40:~> exit                        # 跟 bash 一樣的結果
exit                                                #退出
xxx: sh --norc                                #嘗試 --norc
kenny@x40:~> exit                        #也一樣,沒影響
exit                                                #退出
xxx: export PS1                                #將 PS1 輸出為 env
xxx: sh                                                #進入 sh
kenny@x40:~> exit                        #還是被 reset ,應是執行 ENV 路徑的關係
exit                                                #退出
xxx: sh --norc                                #使用 --norc
kenny@x40:~> exit                        #還是不受影響,ENV 依然有效
exit

結論一:
由上面的測試,可以看到如下的結論:
1)bash 在 --norc 選項下,并不執行 .bashrc
2)sh 有沒 --norc 選項,都會展開 $ENV 并執行之
3)無論如何,當 parent shell 的 PS1 被輸出為 env var 之後,
        就會被 sub shell 繼承,只是最後結果又被 .bashrc 或 $ENV 的 script 修改了。
        換句話來說:
                當 new shell 沒有 PS1 之賦值時(可從 .bashrc 或 $ENV 的 script 來設定),
                shell prompt 會採用 default 值:\s-\v\$
        * 我相信這就是 FH 兄整個問題的原因所在了。

實驗三:為了驗證上面第 3 點,以下專門針對 ENV 的有無進行測試:

kenny@x40:~> echo "$PS1"
$(ppwd \l)\u@\h:\w>                         # 這是原 PS1 值
kenny@x40:~> unset ENV                # 取消 ENV
kenny@x40:~> echo "$ENV"
                                                        #確認 ENV 已被取消
kenny@x40:~> PS1="xxx: "        #修改 PS1,但不做輸出
xxx: bash                                        #進入 bash
kenny@x40:~> exit                        #看來不受 ENV 影響
exit                                                #退出
xxx: bash --norc                                #使用 --norc
bash-3.1$ exit                                #被設為 bash default,看來也與 ENV 無關
exit                                                #退出
xxx: export PS1                                #將 PS1 輸出
xxx: bash                                        #進入 bash
kenny@x40:~> exit                        #一樣,看來還是被 .bashrc 改了
exit                                                #退出
xxx: bash --norc                                #不用 rc
xxx: exit                                        #注意!這次從 env 裡繼承了 PS1 值
exit

結論二:
從上面看來,bash 根本就不受到 $ENV 的影響,但卻受到 .bashrc 影響。
實驗一跟實驗三基本上沒有差異。

實驗四:下面驗證 sh:

kenny@x40:~> echo "$PS1"
$(ppwd \l)\u@\h:\w>                         #這是原 PS1 值
kenny@x40:~> unset ENV                #取消 ENV
kenny@x40:~> echo "$ENV"
                                                        #確認取消
kenny@x40:~> PS1="xxx: "        #修改 PS1,但不輸出
xxx: sh                                                #進入 sh
sh-3.1$ exit                                        #被設為 default
exit                                                #退出
xxx: sh --norc                                #使用 --norc
sh-3.1$ exit                                        #看來沒影響
exit                                                #退出
xxx: export PS1                                #輸出 PS1
xxx: sh                                                #進入 sh
xxx: exit                                        #繼承了 PS1!
exit                                                # 退出
xxx: sh --norc                                #使用 --norc
xxx: exit                                        #還是繼承 PS1!
exit

結論三:
看來, sh 的確是受到 ENV 的影響而改變了 PS1 的值,但卻不受 .bashrc 影響。

實驗五:專門針對 PS1 的賦值來測試:
kenny@x40:~> unset ENV                #取消 ENV
kenny@x40:~> export PS1="xxx: "        #修改 PS1,并一同輸出
xxx: bash --norc                                #以 --norc 進入 bash,避免 PS1 被修改
xxx: exit                                        #繼承了 PS1
exit                                                #退出
xxx: sh                                                #進入 sh
xxx: exit                                        #繼承了 PS1
exit                                                #退出
xxx: unset PS1                                #取消 PS1,這是測試重點!!
bash --norc
bash-3.1$ exit                                #bash 的 PS1 設為 default
exit                                                #退出
sh
sh-3.1$ exit                                        #sh 的 PS1 也為 default
exit

所以,這印證了結論一第三點,也就是:
---如果 PS1 為 env,那就繼承;如果沒賦值,就使用 default。

實驗六:再來針對 FH 兄關於 vi 的疑問:
kenny@x40:~> unset ENV                #取消 ENV
kenny@x40:~> export PS1="xxx: "        #修改 PS1,并一同輸出
xxx: set | grep 'PS[0-9]'                #抓取 PS 相關的值
PS1='xxx: '                                        #確認 PS1 被修改
PS2='> '
PS4='+ '

xxx: vi                                        #進入 vi
                                                #然後我執行--- :!set | grep 'PS[0-9]'
PS4='+ '                                        #結果只有 PS4 (哈別去問 sony 哦)

Press ENTER or type command to continue
                                                #然後我再執行--- :!sh
sh-3.1$ exit                                #結果 PS1 設為 default,印證了結論一第 3 點。
exit                                        #返回 vi

Press ENTER or type command to continue
                                                #退出 vi
xxx:

------
好了,實驗結束。
我不敢保證我的實驗是完整而正確的,這有待其它朋友進一步來檢驗。
但從結果來看,我會認同 kenduest 兄的說法。
至於 FH 兄,在下的建議如下:
1)可能兄台平時在清茶跟人吵架習慣了,大可不必將此習性帶到技術版面裡。
2)謙虛永遠是受益的,這跟年紀或經驗無關。
3)嚴謹的實驗是有必要的,如果只是一兩個現象就過早歸納結論,有時會有錯漏。
4)假如我批評得不對,請您原諒。

謝謝!

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
3 [报告]
发表于 2007-01-10 10:10 |显示全部楼层
前面我們已經給出結論了:
---如果 PS1 為 env,那就繼承;如果沒賦值,就使用 default。

kenduest 兄也驗證出 vi 所調用的 shell 不是 interactive,因為有 -c 選項。
因此 vi 的 shell 并沒有 PS1, 也就是“如果沒賦值,就使用 default”。
這樣你明白了嗎?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
4 [报告]
发表于 2008-02-17 20:52 |显示全部楼层
感謝 wwy 兄的指教與補充。
不過,您的問題,我一時沒能驗證。且憑直覺回答如下:
1)應該不一樣。如果帶了 BASH_ 的字眼,應該只有 bash 才會參考。就算 sh 是 bash 的 link,也不參考。
2)這個還需進一步在不同的版本測試。不敢妄答。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP