Tip 11. 函数的返回值
-
和大多数语言一样,返回值用
return(如果不指定则返回最后一条语句的返回值)。但和大多数语言不一样,shell中返回值只能为整数。fun1() { return 100 # 正确 } fun2() { return "fun2" # 错误 } -
调用时接收不能用
foo=fun1(实际上这不是调用函数fun1,而是将字符串fun1赋给foo)。得先调用fun1,再用$?得到返回值。foo=fun1 # 错误 echo $foo # 输出fun1 fun1 echo $? # 输出100
Tip 12. 命令的返回值
一般的linux命令,都可以在shell中直接使用,我们也经常利用这些命令(包括Tip 11中的自定义函数)的标准输出(管道1)来当作”hacked”返回值。
foo() {
echo "foo()"
return 100
}
out=$(foo)
echo $? # 100
echo $out # foo()
out=$(ls)
echo $? # 0
echo $out # 当前目录的文件列表
这里也有一个坑要注意:在自定义函数返回结果时,所有此函数中的标准输出都会返回,而不是最后一条标准输出:
foo() {
echo "$FUNCNAME is being invoked"
echo "foo()"
}
out=$(foo)
[[ $out == "foo()" ]] && echo "true" # 不会输出true因为out的值是两条echo
Tip 13. 调用shell时传入read等待的输入
假设有一个程序等待用户的输入yes or no:
#!/bin/bash
# read.sh
echo "Input yes or no:"
read input
echo $input
而这个脚本被串在另一个自动化脚本中,这个等待用户输入的行为会打断自动化。这种情况下可以用 echo yes | ./read.sh 来做到。
那么再考虑这种情况:
#!/bin/bash
# read.sh
echo "Input yes or no:"
read input1
echo "Confirm: Input yes or no:"
read input2
echo $input1
echo $input2
你会怎么做?echo "yes\nyes"?这样你的输入还只是会被赋给input1,\n并没有如你所愿转义并当作两次输入,结果如下:
Input yes or no:
Confirm: Input yes or no:
yesnyes
这种需要多输入的有两种解决方案:
-
使用文件重定向(准备一个文件事先写入分行的输入)
cat input yes yes ./read.sh < input -
echo -e "yes\nyes" | ./read.sh
Tip 14. 变量的范围
bash中的变量分为全局变量和本地变量。
var1=value此类声明的变量为全局变量。若脚本读到(按执行顺序)的变量沿未被赋值,则该变量为空。另外,在shell中也可以引用任何预定义的变量,用printenv可以查看。-
local var1=value此类声明的变量为局部变量,且只能用在函数中。PS:变量无需声明就可以使用,但通过
declare option var声明可以限制变量的类型。optioncould be:- -r read only variable
- -i integer variable
- -a array variable
- -f for funtions
- -x declares and export to subsequent commands via the environment
Tip 15. 数组
从一个初学者的角度,bash的数组语法是比较晦涩的,远没有其他高级语言那么直观。thegeekstuff上的这篇文章是很不错的入门材料。
Tip 16. 重用函数
假设我们有一个shell:
#!/bin/bash
# util.sh
func1() {...}
func2() {...}
那么在别的shell中可以用以下方法重用:
source ./util.sh
func1
func2
Tip 17. alias转义
在写shell来自动化一些任务时,你可能不想看到烦人的confirm yes or no的信息,所以经常性地会使用类似-f的flag。但这些命令有可能其实是一个alias:
hweicdl@hweicdl-t430:~$ alias rm
alias rm='rm -i'
在上面这个例子的环境中,rm -f相当于rm -f -i,而-i会覆盖-f。所以在上面的环境中rm -f还是会要求你confirm是否删除。解决方案是\rm -f来使用原始的rm。
Tip 18. 删除\^M
^M英文名叫garbage character,出现在文件的末尾,一般是由于windows上以\r\n结尾的文件传到linux上来导致的。
以下几种方法都可以删除它:
sed -i -e 's/^M//' filename- 在vi下,
:%s/^M//g dos2unix filename(可能需要先安装dos2unix)
但要注意的是这个garbage character其实是一个字符,在匹配的时候不能分别输入^和M,得先按住Ctrl,再按V和M。
Tip 19. I/O重定向
在linux上,一般至少有三个文件是打开着的:stdin(输入,默认来自键盘),stdout(标准输出,默认输出至屏幕)和stderr(错误输出,默认输出至屏幕)。这三个文件被分配了三个FD(File Descriptor):0,1,2。我们在操作bash的输入输出重定向,需要和它们打交道。
我常用的几个操作包括:
command < input-file > output-file命令接收input-file的输入,并将输出重定向至output-file> file清空一个文件的内容command &> /dev/null将标准输出和错误都丢弃,等价于command 2>&1 1>/dev/nullecho "err info..." >&2在捕获住的错误放至错误输出,而不是直接丢到屏幕或标准输出
以下两篇文章介绍的比较详细:
- http://cloudbbs.org/forum.php?mod=viewthread&tid=15515
- http://www.tldp.org/LDP/abs/html/io-redirection.html
Tip 20. Here Document
在打印脚本的help信息时,可能我们会这么做:
echo "usage: blabla..."
echo "-a means..."
echo "-b means..."
也可以这么写:
cat << EOF
usage: blabla...
-a means...
-b means...
EOF
这个语法在一个脚本执行时动态生成另一个脚本尤其方便:
cat << EOF > another_script.sh
#!/bin/bash
command1...
command2...
EOF
bash another_script.sh
这样就不用一句句echo了。