读到一篇文章《Ten Things I Wish I’d Known About bash》,所以有了这个畅销书式的标题,一些笔记。
感觉作者写这本书主要是为了推销他的新书《Learn Bash the Hard Way》,不过其中十个关于Bash 的点,倒是挺有趣。
1) ` ` vs $()
这2个符号的效果一样,它们包含的内容都会被执行,然后再把结果赋值给变量,或者传递给其他命令,很常用:
$ echo `ls`
$ echo $(ls)
我个人常用` `
,$() 不常用,它们2个有啥区别呢?看个例子:
$ echo `echo \`echo \\\`echo inside\\\`\``
$ echo $(echo $(echo $(echo inside)))
2条语句效果一样,不过后者可读性明显好太多,以后写这种嵌套命令的时候,用$()
吧,不然debug 起来得瞎眼。
参考:
- Why is $(...) preferred over `...` (backticks)?
- What is the difference between $(command) and `command` in shell programming?
这里有个小插曲,我不知道怎么用Markdown 写出反引号(backticks)内一对反引号的效果: ` `
,发了一条tweet,得到了答案,这个符号好像也可以叫:grave accent,沉音符:
`` ` ` ``
2) 通配符 vs 正则表达式
这2个是完全不一样的东西,不懂作者说容易搞混。。。作者给的例子:
#输出目录下所有的文件
$ ls *
#输出目录下所有以. 开头的文件,是通配符,不是正则
$ ls .*
3) 返回码(Exit Codes)
Bash 的世界,0 是正常,非0 是异常。echo $?
可以得到上一条命令的返回码。其实是不是应该按照翻译叫退出码,不过编译语言里return
都叫返回码嘛。
常常用grep 的返回码来判断特定内容是否存在,是因为如果存在grep 会返回0,不存在返回1,放在if 语句里面,非常直观、方便!见下文。
4) if 语句,[ 和 [[
if grep not_there /dev/null
then
echo hi
else
echo lo
fi
以上脚本执行,输出lo ,非常直观有木有。
[
和[[
的差别,前者好像是内置命令,后者是关键词,一般尽量用后者就是了,比较方便。详细区别对比:BASH 中单括号和双括号
# 直接执行会出错,$(grep note_there /dev/null) 输出为空,就变成了[ = '' ] ,
# 这也就是为什么常常在一些老脚本里面看到这样的语句: [ x$(...) = '']
if [ $(grep not_there /dev/null) = '' ]
then
echo -n hi
else
echo -n lo
fi
# [[ 就没有以上困扰
if [[ $(grep not_there /dev/null) = '' ]]
then
echo -n hi
else
echo -n lo
fi
5) set
脚本开头我一般都会加上:
set -eu
-u 表示遇到没定义的变量的时候,直接退出,可以防止如下的悲剧:
rm -rf ${ROOT}/
如果${ROOT}
没赋值,会发生什么?
-e 表示执行过程中遇到非0 的退出状态码,直接退出,结束执行,也可以防止某些异常情况。
完整的选择列表和解释:Advanced Bash-Scripting Guide: Chapter 33. Options。
6) <()
作者说的这个我倒不常用,看起来挺方便。
$ grep somestring file1 > /tmp/a
$ grep somestring file2 > /tmp/b
$ diff /tmp/a /tmp/b
可以简化为:
diff <(grep somestring file1) <(grep somestring file2)
7) Quoting
A='123'
echo "$A"
echo '$A'
单引号里面的内容不会展开,输出结果为:
123
$A
作者文章里面这个例子:
mkdir -p tmp
cd tmp
touch a
echo "*"
echo '*'
不知道是因为版本原因还是配置问题,在我的机器上测试,都是输出 *
,作者说的意想不到的结果大概是:
echo *
会输出当前目录下所有的文件名。
8) 最常用的三个快捷操作
!!
,重复执行上一条命令~
,展开为当前用户的home 目录
作者列了他最常用的3个快捷操作:
!@
,展开为上一条命令的所有参数;!:1-$
:这条命令看着有点复杂,!
表示上一条命令,:
是分隔符,后面就是表示取到第几位。!:2-3
,展开为上一条命令的参数中的第2到第3位的内容。
bash-3.2$ echo 1 2 3 4 5
1 2 3 4 5
bash-3.2$ echo !:2-3
2 3
:h
grep isthere /long/path/to/some/file/or/other.txt
cd !$:h
!$:h
展开为 上一条命令最后一个参数的目录路径:"/long/path/to/some/file/or"。
9) 启动顺序
作者放了1个图,左边是Bash,右边是Zsh,来源是:Shell startup scripts。
非常有趣、直观,顺着一种颜色看,Bash 启动过程,期间加载的文件,一目了然。读这篇文章,最大的收获就是见到这张图。