什么是bash、dash
Bash(GNU Bourne-Again Shell)是许多Linux平台的内定Shell,事实上,还有许多传统UNIX上用的Shell,像tcsh、csh、ash、bsh、ksh等等。
GNU/Linux 操作系统中的 /bin/sh 本是 bash (Bourne-Again Shell) 的符号链接,但鉴于 bash 过于复杂,有人把 bash 从 NetBSD 移植到 Linux 并更名为 dash (Debian Almquist Shell),并建议将 /bin/sh 指向它,以获得更快的脚本执行速度。Dash Shell比 Bash Shell小的多,符合POSIX标准。
Debian和Ubuntu中,/bin/sh默认已经指向dash,这是一个不同于bash的shell,它主要是为了执行脚本而出现,而不是交互,它速度更快,但功能相比bash要少很多,语法严格遵守POSIX标准。
要知道自己自己的/bin/sh指向那个解析器,可使用 ls -al /bin/sh 查看
shell
netsky@netsky:~$ ls -al /bin/sh
lrwxrwxrwx 1 root root 4 Mar 23 2022 /bin/sh -> dash
bash和dash语法区别
bash和dash语法上的主要区别有:
1. 定义函数
dash中没有function关键字,而bash可以有也可以没有function关键字
shell
# dash这里没有function关键字,使用function,将在"("附近报语法错误
function func1(){
echo "print func1"
}
# 该写法bash和dash均支持
func2(){
echo "print func2"
}
func1
func2
结论:定义函数时不使用function关键字达到通用的目的。
2. select var in list; do command; done
dash不支持该写法,需要改成while read case 来实现
shell
# dash不支持select选择语句
select animal in lion tiger panda flower; do
if [ "$animal" = "flower" ]; then
echo "Flower is not animal."
break
else
echo "Choose animal is: $animal"
fi
done
# bash和dash均支持while read case 写法
while true
do
cat << EOF
1) lion
2) tiger
3) panda
4) flower
EOF
read -p "input :" animal
case "$animal" in
1) echo "lion"
;;
2) echo "tiger"
;;
3) echo "panda"
;;
*) echo "not animal"
break
;;
esac
done
结论:使用while read case写法达到通用的目的。
3. {0...10}
dash不支持{m...n}展开,识别为单个整体
shell
# dash不支持{m..n}展开
for i in {0..10}
do
echo $i
done
# bash和dash均支持
for i in $(seq 11)
do
echo $i
done
结论:使用seq或者其它loop写法,为了灵活使用的话,可使用bash,并使用bash 脚本名称 的方式运行脚本。
4. here strings
dash不支持here string,改成here document
shell
# dash不支持here strings
cat <<< "here strings"
# bash和dash均支持here document
cat << EOF
here document
EOF
结论:使用here document 达到通用的目的。
5. >&word重定向标准输出和标准错误
当word为非数字时,bash中>&word变成重定向标准错误和标准输出到word中
而dash中>&word,word不支持非数字,替代方法是: >word 2>&1
shell
# bash支持的写法
echo "1234" >&err1.log
# bash和dash均支持的写法
echo "5678" >err2.log 2>&1
结论:使用通用的重定向标准输入和标准错误写法。
6. 数组
bash支持数组,而dash不支持,需要替代
shell
# bash支持的写法
array=(test001 test002 test003)
echo ${array[2]}
# bash和dash均支持的写法,需注意会替换掉传参,需及时赋值
var="test001 test002 test003"
set -- $var
echo ${3} # 超过10个,需注意${10}写法
结论:bash很灵活,如果需要通用,需要使用替代写法。
7. 子字符串扩展
bash支持${parameter:offset:length}等写法
而dash不支持这类扩展,替代方法是使用其它外部命令
shell
str="Abcdefgh"
# bash和dash均支持的写法,cut从第N位开始
echo $str | cut -b 4-5
# bash支持的写法,跳过(offset)M位,从M+1位开始
echo ${str:3:2}
结论:bash很灵活,如果需要通用,需要使用替代写法。
8. 大小写转换
bash支持 p a r a m e t e r p a t t e r n , {parameter^pattern}, parameterpattern,{parameter^^pattern}大小写替换写法
而dash不支持这类扩展,替换方法是使用使用其它外部命令(如tr/sed/awk)
shell
str1="abcdefgh"
str2="ABCDEFGH"
# bash和dash均支持
echo ${str1} | sed 's/^\b[a-z]/\U&/'
echo ${str2} | sed 's/^\b[A-Z]/\L&/'
echo ${str1} | tr [:lower:] [:upper:]
echo ${str2} | tr [:upper:] [:lower:]
# bash支持 ^(大写), ,(小写), ~(反转)
echo ${str1^}
echo ${str1^^}
echo ${str2,}
echo ${str2,,}
结论:bash很灵活,如果需要通用,需要使用替代写法。
9. 进程替换<(command), >(command)
bash支持进程替换
dash不支持,替代方法是使用临时文件转换
shell
# bash和dash均支持临时文件的写法,这里只是示例
echo "test001" > 10.tmp
while read user
do
echo $user
done < 10.tmp
# bash支持进程替换,注意 <() 是个整体
read user < <(echo "test002")
echo $user
结论:bash很灵活,如果需要通用,需要使用替代写法。
10. [ str1 = str2 ]和[ str1 == str2 ]
bash两种方法均支持
dash仅支持=写法
shell
str="A"
# bash和dash均支持
[ $str = "A" ] && echo 1 || echo 2
# bash支持
[ $str == "A" ] && echo 11 || echo 12
结论:使用=写法达到通用的目的。
11. [[]] 加强版test
bash支持[[]] 写法,可实现正则匹配等强大功能
dash不支持该语法,需要使用替代写法。
shell
tel=23800138000
# bash和dash均支持,使用外部命令方式
echo "$tel" | sed 's/2[0-9]\{10\}/1/'
# bash支持
[[ $tel =~ 1[0-9]{10} ]] && echo 1 || echo 2
结论:bash很灵活,如果需要通用,需要使用替代写法。
12. for ((expr1; expr2; expr 3)); do list; done
bash支持C语言格式的for循环
dash不支该语法,需要使用替代写法(如:while $((expr)))。
shell
# bash和dash均支持
i=0
while [ $i -lt 10 ]
do
echo $i
i=$((i+=1))
done
# bash支持
for ((i=0;i<10;i++))
do
echo $i
done
结论:bash很灵活,如果需要通用,需要使用替代写法。
13. let命令和((expression))
bash支持let,也支持((expression))
dash不支持,替代方法是采用$(())或者使用其它外部命令做计算
shell
a=10
# bash和dash均支持下面两种写法
a=$((a+=1))
echo $a
a=$(expr $a + 1)
echo $a
# bash支持let和((expression))写法
let a++
echo $a
((a++))
echo $a
结论:bash很灵活,如果需要通用,需要使用替代写法。
14. $((expression))
bash支持i++,++i,i--这样的表达式
dash不支持++,--,替代方法是i+=1,i=i+1
shell
a=10
# bash和dash均支持
echo $((a=a+1))
# bash支持++
echo $((a++))
结论:bash很灵活,如果需要通用,需要使用替代写法。
总结
bash相对于dash来说很灵活,有更多的语法支持。
需要通用的情况下,需要注意差异,使用符合POSIX标准的写法;如果确定能使用bash的情况下,将能更灵活使用。
需要特别注意的是:
- 如果shell脚本是使用bash编写,但当前的/bin/sh链接到的是dash,那么"sh 脚本" 将会使用dash来执行,而忽视头部shell指示!
- 如果shell脚本是使用bash编写,请使用"bash 脚本" 或者 "./脚本" 的方式执行脚本。