我的脚本如何确定是bash还是dash运行它?


13

我正在两个不同的系统上运行全新的Oneiric安装(即不是升级),并且遇到了一系列看似相关的问题。

最令人沮丧的是,当我使用从Mac OS X附带的.profile和.bashrc时,通过LightDM登录到X会使我立即注销。我相信这是由于以下事实造成的:当运行“ / bin / sh”时,它的行为类似于/ bin / dash,但仍将$ SHELL变量设置为/ bin / bash。

外推法

我有一个巨大的.bashrc。如果需要,您可以在这里看到它,但是它的内容可能不相关,除了它充满了bashisms的事实,而且它在xterm内或虚拟控制台上没有错误地工作。

我的.profile样子如下(略):

case $SHELL in 
*bash*)
    if [ -f $HOME/.bashrc -a -r $HOME/.bashrc ]; then
        . $HOME/.bashrc
    fi
    ;;
esac

如果我尝试通过LightDM登录到X,它将立即使我注销。我收到.xsession-errors与.bashrc相关的错误,看起来像这样(缩写):

/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found

就像我说的那样,当我从虚拟控制台运行bash时,不会出现这些错误。此外,如果删除.profile,则可以正常登录X。(我也可以登录到虚拟控制台,并startx用来启动有效的X会话,但这当然不是一个长期的解决方案。)

但是,我发现,如果运行/bin/sh -l,我得到错误。这是一个示例会话(请注意:我简化为bash提示符bash>,而sh提示符只是$):

bash> echo $SHELL
/bin/bash
bash> echo $BASH_VERSION
4.2.10(1)-release
bash> /bin/sh -l
/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found
$ echo $SHELL
/bin/bash
$ echo $BASH_VERSION

$

问题1:为什么会这样?

我知道/ bin / sh现在指向破折号而不是bash,但是如果这是真的,那么为什么$SHELL仍然返回/bin/bash

Q2:我该如何解决?

有办法解决这个问题吗?我想保持我的配置文件加载.bashrc,以便在登录和非登录外壳上都具有相同的环境,但是显然我只希望它为bash本身加载,而不是/ bin / sh伪装成bash。

您可能已经注意到上面$ BASH_VERSION变量的内容有所不同。我试过将我的.profile包装成这样的东西:

if [ -n $BASH_VERSION ]; then
    # the rest of my .profile as above
fi

-n只如果字符串的长度为非零在上述会议上试验应返回true,但是,即使当我跑下/bin/sh -l它返回$ BASH_VERSION一个空字符串,当它包含在我的.profile这样,它通过了测试!他们继续获取我的.bashrc并给我和以前一样的错误。

现在我真的困惑。


请注意,该值dash -l也显示$SHELL具有/bin/bash
Scott Severance,2012年

3
$SHELL/etc/passwd(或getent passwd)中最后一个字段所说的。
暂停,直到另行通知。

@DennisWilliamson 谢谢,这就是我找到正确答案所需要知道的。
Micah R Ledbetter,2012年

你这样做是错的。您应该将非bash专用的环境放在中~/.profile,bash专用的东西放在中~/.bashrc,并同时提供~/.bash_profile源代码。
nyuszika7h 2015年

Answers:


12

您可以为您做一个$BASH_VERSION空白的事实dash

if [ "$BASH_VERSION" = '' ]; then
    echo "This is dash."
else
    echo "This is bash."
fi

2
“ x”技术是古老的,仅在古代炮弹中才需要。使用if [ "$BASH_VERSION" = '' ]
暂停,直到另行通知。

@DennisWilliamson:谢谢。我曾以为您的技术是Bash特有的,但我只是将其放在Dash中并奏效了。我已经编辑了答案。
Scott Severance,2012年

或只是使用-n,或一无所有。(不过+1。= ''效果很好。)
Eliah Kagan

5

您只需要在变量上使用引号BASH_VERSION即可使用-n

if [ -n "$BASH_VERSION" ];then
 echo "this is bash"; 
else 
 echo "this is dash";
fi

1
由于[ "$EMPTY_STRING" ]评估为假,因此您甚至不需要-n。您只需要引用变量。
jeberle '16

2

/proc/[PID]/cmdline看什么剧本正在与并试运行它所包含的内容。该$$变量将为我们提供运行中的外壳的PID。这样我们可以制作一个这样的脚本,

#!/bin/bash
if grep -q 'bash' /proc/$$/cmdline ;
then
    echo "This is bash"
else
    echo "This is some other shell"
fi

这是对相同脚本的测试:

$> bash test_script.sh                                                                                                
This is bash
$> dash test_script.sh                                                                                                
This is some other shell

在Mac上将无法使用。检查$ BASH_VERSION。
奥斯汀·伯克

2
@AustinBurk不需要在Mac上运行。这是Ask Ubuntu。
TheWanderer

@ Zacharee1哦,该死,我没注意:,)
Austin Burk

我不想根据您的意图进行编辑,但是我建议提及此方法的局限性。Bash不需要bash它的名字;bash通过具有其他名称的符号链接运行可执行文件的情况并不少见。通常,人们仍然会考虑使用Bash。此外,模式匹配任何地方/proc/$$/cmdline,这应该是可以修复的,但请记住,在参数cmdline为空字符分隔。grep -qE '(^|/)bash$'感觉它应该起作用,但是当有任何论据时给出误报bash
伊莱亚·卡根

@EliahKagan随时随时编辑我的答案-您拥有足够的专业知识,因此我知道您的编辑只能提供改进。答案是在我比现在更加环保的时候写的。
Sergiy Kolodyazhnyy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.