ubuntu上的sh链接到dash


最近同事写的shell脚本在ubuntu上跑时总走不对if的分支。发现ubuntu上的shell默认是bash,但sh对应的是dash,这个需要注意。
1
ubuntu上sh连到dash:
zxw@hostname1:~$ uname -a
Linux hostname1 3.11.0-15-generic #25~precise1-Ubuntu SMP Thu Jan 30 17:39:31 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
zxw@hostname1:~$ cat /etc/issue
Ubuntu 12.04.4 LTS \n \l

zxw@hostname1:~$ echo $SHELL
/bin/bash
zxw@hostname1:~$ type sh
sh is hashed (/bin/sh)
zxw@hostname1:~$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 30 2012 /bin/sh -> dash
zxw@hostname1:~$

centos上sh连到bash:
[root@hostalonetest ~]# uname -a
Linux hostalonetest 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
[root@hostalonetest ~]# cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m

[root@hostalonetest ~]# echo $SHELL
/bin/bash
[root@hostalonetest ~]# type sh
sh is /bin/sh
[root@hostalonetest ~]# ls -l /bin/sh
lrwxrwxrwx. 1 root root 4 Sep 1 07:45 /bin/sh -> bash
[root@hostalonetest ~]# echo $SHELL
/bin/bash
[root@hostalonetest ~]#

2
写了个小脚本测试

zxw@hostname1:~$ nl test2.sh
1 #!/bin/bash

2 tt='xx';

3 if [ "$tt" == "YY" ]; then
4 echo "yy"
5 elif [ "$tt" == "xx" ]; then
6 echo "xx"
7 else
8 echo "fuck"
9 fi

3
在ubuntu上走sh用的是dash,测试脚本有错,同时走错了分支
zxw@hostname1:~$ sh test2.sh
test2.sh: 5: [: xx: unexpected operator
test2.sh: 7: [: xx: unexpected operator
fuck

在ubuntu上走默认shell,用的是bash,结果ok
zxw@hostname1:~$ ./test2.sh
xx

4
在centos上走sh用的是bash,结果ok
[root@hostalonetest ~]# sh test.sh
yy
在centos上走默认shell,用的是bash,结果ok
[root@hostalonetest ~]# ./test.sh
yy

5
可以用如下方法修改sh链到bash

ln -s /bin/bash /bin/sh
或者如下:
sudo dpkg-reconfigure dash
出现提示界面问是否要dash的时候,选No就行了。反馈如下:
Removing 'diversion of /bin/sh to /bin/sh.distrib by dash'
Adding 'diversion of /bin/sh to /bin/sh.distrib by bash'
Removing 'diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by dash'
Adding 'diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by bash'
看来第二种方法还是比第一种方法做的完善。

检验结果,已经指向bash:
zxw@hostname1:~$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Sep 15 11:28 /bin/sh -> bash
6
什么是bash ?
Bash(GNU Bourne-Again Shell)是许多Linux平台的内定Shell,事实上,还有许多传统UNIX上用的Shell,像tcsh、csh、ash、bsh、ksh等等,Shell Script大致都类同,当您学会一种Shell以后,其它的Shell会很快就上手,大多数的时候,一个Shell Script通常可以在很多种Shell上使用
什么是dash ?
man结果摘抄部分:
dash is the standard command interpreter for the system. The current version of dash is in the process of being changed to conform with the POSIX 1003.2 and 1003.2a specifications for the shell.
网上抄了段,不知道信息出处:
DASH is a POSIX-compliant implementation of /bin/sh that aims to be as small as possible. It does this without sacrificing speed where possible. In fact, it is significantly faster than bash (the GNU Bourne-Again SHell) for most tasks.
比bash小而快的东西
########################
下面是有些同学翻译或总结的,也放到这儿备查
Ubuntu dash与bash的区别
http://blog.csdn.net/hansel/article/details/9817129 
https://wiki.ubuntu.com/DashAsBinSh
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_title.html
从Ubuntu 6.10开始,默认使用dash(theDebian Almquist Shell)而不是bash(the GNUBourne-Again Shell). 但Login Shell还是bash. 原因是dash更快、更高效,而且它符合POSIX规范。Ubuntu在启动的时候会运行很多shell脚本,使用dash可以加快启动速度。
如果解决bash和dash兼容性导致的问题
在需要bash的脚本的第一行写上"#!/bin/bash" 在Makefile中可以设置
SHELL = /bin/bash
如果需要修改默认为bash,请运行下面命令并选择no。注意这将影响所有的系统脚本。如果有脚本需要dash的特有功能,将引起问题(这种情况比较少)。

sudodpkg-reconfigure dash

在新写的shell脚本里避免使用bash的扩展特性(bashism)。
使用devscripts包的checkbashisms 命令可以检查shell脚本里是否存在bashism. 安装autoconf-doc包运行info autoconf命令可以阅读"Portable Shell" 部分的文档来了解POSIX Shell。 在"["命令(test)中避免使用-a, -o,应该使用多个"[]"命令并用"&&", "||"连接。
例如:下面的shell语句

[\( "$foo" = "$bar" -a -f /bin/baz \) -o ! -x /bin/quux ]

应该替换为:

((["$foo" = "$bar" ] && [ -f /bin/baz ]) || [ ! -x/bin/quux ])

不应该使用"[["命令,而应该使用"["命令使用$((…))而不是((…))做算术计算。不能使用$((n++)), $((--n)) ,而应该是$((n=n+1)) 和$((n=n-1))不要使用{}进行字符扩展,例如/usr/lib/libfoo.{a,so}; 避免使用$'…'扩展转义字符。例如,使用"$(printf '\t')" 代替$'\t'不要使用$"…"进行字符串翻译。应该使用gettext.sh脚本。大部分的${…}进行变量扩展都是可移植的。但是下面的几个不是。
${!...}进行非直接变量扩展,应该使用eval命令。 ${parameter/pattern/string}进行模式替换 ${parameter:offset:length}截取子串不要使用${parm/?/pat[/str]}进行字符替换,而应该使用echo, sed, grep, awk等命令。例如:

OPENGL_VERSION=$(glxinfo| grep "OpenGL version string:")

OPENGL_VERSION=${OPENGL_VERSION/*:/}

应该使用:

OPENGL_VERSION=$(glxinfo| grep "OpenGL version string:" | awk 'BEGIN { FS =":[[:space:]]+" }; { print $2 }')

不要使用${foo:3[:1]}进行子串切割,使用echo, sed, grep, awk等命令。

例如:

string_after="somestring"

string=${string_after:0:3}

应该使用:

string=$(echo$string_after | awk '{ string=substr($0,1, 3); print string; }' )

在case语句中使用[!]而不是[^]。例如:

case"foo" in

[^f]*)

echo 'not f*'

;;

esac

替换为:

case"foo" in

[!f]*)

echo 'not f*'

;;

esac

dash 不支持$LINENO,虽然它是POSIX标准。不要使用$PIPESTATUS避免使用$RANDOM,而应读取/dev/urandom或者/dev/random。例如:

random=`hexdump-n 2 -e '/2 "%u"' /dev/urandom`

一些echo的选项不是portable的,可能其他shell不支持。例如-e, -n函数名前不要加function关键字。不要使用let命令,直接使用=赋值。例如

let time=10 和 time=10一样

let time--和time=$((time-1))一样

bash和dash对local关键字的解释不一样。

local a=5 b=6; //dash:a和b是全局变量, bash则认为a和b是局部变量。

不支持printf %q|%b不要使用select关键字,只有bash才支持。source命令也是bash才支持,应该使用'.'命令路径搜索时,`dash` 不支持 `~` 扩展,应该使用$HOME不支持declare 或 typesetbash和dash对ulimit和type有不同的选项time是bash内置的命令,但是在dash下需要使用time程序kill -[0-9] or -[A-Z]是bash内置的命令在bash里,如果read没有接变量,则会保存在REPLY变量里。在dash应该使用read REPLY替代。不要使用<<<,而是使用<<替代。例如:

$cat <<<"$HOME is where the heart is."

/home/ralphis where the heart is.

替换为:

$cat <<E

>$HOME is where the heart is.

>E

/home/ralphis where the heart is.

$

#############################

Dash与Bash的语法区别

http://blog.163.com/hlz_2599/blog/static/142378474201182195320441/

如今Debian和Ubuntu中,/bin/sh默认已经指向dash,这是一个不同于bash的shell,它主要是为了执行脚本而出现,而不是交互,它速度更快,但功能相比bash要少很多,语法严格遵守POSIX标准,下面简要列举下从bash迁移到dash一般需要注意的问题

1.定义函数

bash: function在bash中为关键字

1 2 3 4 5 6 igi@gentoo ~ $ foo(){ echo $0;} igi@gentoo ~ $ foo /bin/bash igi@gentoo ~ $ function foo2(){ echo $0;} igi@gentoo ~ $ foo2 /bin/bash

dash: dash中没有function这个关键字

1 2 3 4 5 $ foo(){ echo $0;} $ foo dash $ function foo2(){ echo $0;} dash: Syntax error: "(" unexpected

2.select var in list; do command; done

bash:支持

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 igi@gentoo ~ $ select input in A B > do > case $input in > A) > echo 'Input:A' > break > ;; > B) > echo 'Input:B' > break > ;; > esac > done 1) A 2) B #? 1 Input:A igi@gentoo ~ $ echo $0 /bin/bash

dash:不支持, 替代方法:采用while+read+case来实现

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 menu(){ echo -n "1)A;\n2)B\n>";} menu while read input do case $input in 1) echo 'A' break ;; 2) echo 'B' break ;; *) menu continue ;; esac done

3. echo {0..10}

bash:支持{n..m}展开

1 2 3 4 igi@gentoo ~ $ echo $0 /bin/bash igi@gentoo ~ $ echo {0..10} 0 1 2 3 4 5 6 7 8 9 10

dash:不支持,替代方法, 采用seq外部命令

1 2 3 4 5 6 $ echo $0 dash $ echo {0..10} {0..10} $ echo `seq 0 10` 0 1 2 3 4 5 6 7 8 9 10

4. here string

bash:支持here string

1 2 3 4 igi@gentoo ~ $ cat <<<"string" string igi@gentoo ~ $ echo $0 /bin/bash

dash:不支持, 替代方法:可采用here documents

1 2 3 4 5 6 7 8 $ echo $0 dash $ cat <<<"string" dash: Syntax error: redirection unexpected $ cat <<EOF > string > EOF string

5. >&word重定向标准输出和标准错误

bash: 当word为非数字时,>&word变成重定向标准错误和标准输出到文件word, 常见用法>&/dev/null

1 2 3 4 5 6 7 8 9 igi@gentoo ~/test $ ls a igi@gentoo ~/test $ ls a b ls: cannot access b: No such file or directory a igi@gentoo ~/test $ ls a b >&/dev/null igi@gentoo ~/test $ ls a b >/dev/null 2>&1 igi@gentoo ~/test $ echo $0 /bin/bash

dash: >&word, word不支持非数字, 替代方法: >word 2>&1; 常见用法 >/dev/null 2>&1

1 2 3 4 5 6 7 8 9 10 11 $ echo $0 dash $ ls a a $ ls a b ls: cannot access b: No such file or directory a $ ls a b >&/dev/null dash: Syntax error: Bad fd number $ ls a b >/dev/null 2>&1 $

6. 数组

bash: 支持数组, bash4支持关联数组

1 2 3 4 5 igi@gentoo ~/test $ echo $0 /bin/bash igi@gentoo ~/test $ array=( a b c ) igi@gentoo ~/test $ echo ${array[2]} c

dash: 不支持数组,替代方法, 采用变量名+序号来实现类似的效果

1 2 3 4 5 6 7 8 9 $ for i in a b c > do > id=$((${id:=-1}+1)) > eval array_$id=$i > done $ echo ${array_1} b $ echo $0 dash

很蛋疼的方法,非不得以不建议这么用

7. 子字符串扩展

bash: 支持${parameter:offset:length},${parameter:offset}

1 2 3 4 5 6 7 igi@gentoo ~/test $ string='hello' igi@gentoo ~/test $ echo ${string:1:3} ell igi@gentoo ~/test $ echo ${string:1} ello igi@gentoo ~/test $ echo $0 /bin/bash

dash: 不支持, 替代方法:采用expr或cut外部命令代替

1 2 3 4 5 6 7 8 9 10 11 12 $ string='hello' $ expr substr "$string" 2 3 ell $ echo "$string" | cut -c2-4 ell $ expr substr "$string" 2 "${#string}" ello $ echo "$string" | cut -c2- ello $ echo $0 dash $

8. 大小写转换

bash: 支持${parameter^pattern},${parameter^^pattern},${parameter,pattern},${parameter,,pattern}

1 2 3 4 5 6 7 8 9 igi@gentoo ~/test $ string="abcABC" igi@gentoo ~/test $ echo ${string^^} ABCABC igi@gentoo ~/test $ echo ${string,,} abcabc igi@gentoo ~/test $ echo ${string^^b} aBcABC igi@gentoo ~/test $ echo $0 /bin/bash

dash: 不支持,替代方法:采用tr/sed/awk等外部命令转换

1 2 3 4 5 6 7 8 $ string='abcABC' $ echo "$string" | tr '[a-z]' '[A-Z]' ABCABC $ echo "$string" | tr '[A-Z]' '[a-z]' abcabc $ echo "$string" | sed 's/b/\U&/g' aBcABC $

9. 进程替换<(command), >(command)

bash: 支持进程替换

1 2 3 4 5 igi@gentoo ~ $ diff <(seq 3) <(seq 4) 3a4 > 4 igi@gentoo ~ $ echo $0 /bin/bash

dash: 不支持, 替代方法, 通过临时文件中转

1 2 3 4 5 6 7 8 9 10 $ diff <(seq 3) <(seq 4) dash: Syntax error: "(" unexpected $ seq 3 >tmp1 $ seq 4 >tmp2 $ diff tmp1 tmp2 3a4 > 4 $ echo $0 dash $

10. [ string1 = string2 ] 和 [ string1 == string2 ]

bash: 支持两者

1 2 3 4 5 6 igi@gentoo ~ $ [ 'a' = 'a' ] && echo 'equal' equal igi@gentoo ~ $ [ 'a' == 'a' ] && echo 'equal' equal igi@gentoo ~ $ echo $0 /bin/bash

dash: 只支持=

1 2 3 4 5 6 7 $ [ 'a' = 'a' ] && echo 'equal' equal $ [ 'a' == 'a' ] && echo 'equal' [: 2: a: unexpected operator $ echo $0 dash $

11. [[ 加强版test

bash: 支持[[ ]], 可实现正则匹配等强大功能

1 2 3 4 igi@gentoo ~ $ [[ 'xyz123' =~ xyz[0-9]+ ]] && echo 'equal' equal igi@gentoo ~ $ echo $0 /bin/bash

dash: 不支持[[ ]], 替代方法,采用外部命令

1 2 3 4 5 6 7 $ [[ 'xyz123' =~ xyz[0-9]+ ]] && echo 'equal' dash: [[: not found $ echo 'xyz123' | grep -q 'xyz[0-9]\+' && echo 'equal' equal $ echo $0 dash $

12. for (( expr1 ; expr2 ; expr3 )) ; do list ; done

bash: 支持C语言格式的for循环

1 2 3 4 5 6 7 igi@gentoo ~ $ for((i=0;i<=3;i++));do echo "$i";done 0 1 2 3 igi@gentoo ~ $ echo $0 /bin/bash

dash: 不支持该格式的for, 替代方法,用while+$((expression))实现

1 2 3 4 5 6 7 8 9 10 11 12 13 $ i=0 $ while [ "$i" -le 3 ] > do > echo "$i" > i=$((i+1)) > done 0 1 2 3 $ echo $0 dash $

13. let命令和((expression))

bash: 有内置命令let, 也支持((expression))方式

1 2 3 4 5 6 7 8 9 igi@gentoo ~ $ i=0 igi@gentoo ~ $ let i++ igi@gentoo ~ $ echo $i 1 igi@gentoo ~ $ ((i++)) igi@gentoo ~ $ echo $i 2 igi@gentoo ~ $ echo $0 /bin/bash

dash: 不支持,替代方法,采用$((expression))或者外部命令做计算

1 2 3 4 5 6 7 $ i=0 $ i=$((i+1)) $ echo $i 1 $ echo $0 dash $

14. $((expression))

bash: 支持id++,id--,++id,--id这样到表达式

1 2 3 4 5 6 7 8 9 10 11 igi@gentoo ~ $ i=0 igi@gentoo ~ $ echo $((i++)) 0 igi@gentoo ~ $ echo $i 1 igi@gentoo ~ $ echo $((++i)) 2 igi@gentoo ~ $ echo $i 2 igi@gentoo ~ $ echo $0 /bin/bash

dash: 不支持++,--, 替代方法:id+=1,id-=1, id=id+1,id=id-1

1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ i=0 $ echo $((i++)) dash: arithmetic expression: expecting primary: "i++" $ echo $i;i=$((i+1)) 0 $ echo $i 1 $ echo $((i+=1)) 2 $ echo $i 2 $ echo $0 dash $

参考:

https://wiki.ubuntu.com/DashAsBinSh

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_title.html

-----------------

转载请著明出处:
blog.csdn.net/beiigang

相关内容