Bash函数的技巧
- 递归函数
递归调用,可以调用自身的函数
F() { echo $1; F hello; sleep 1; }
Fork炸弹
递归函数是能够调用自身的函数,这种函数必须有退出条件,否则就会不断地生成自身,直到系统耗尽所有的资源或是崩溃
:(){ :|:&};:
这个函数会一直生成新的进程,最终形成拒绝服务攻击
函数调用前的&将子进程放进后台。这段危险的代码能够不停地衍生出进程,因而被称为Fork炸弹
可以通过修改配制文件/etc/security/limits.conf中的nproc来限制可生成的最大进程数,进而阻止这种攻击
# 将所有用户可生成的进程数限制为100
hard nproc 100
导出函数
函数也能像环境变量一样用export导出,如此一来,函数的作用域就可以扩展到子进程中
$ function getIP() { /sbin/ifconfig $1 | grep 'inet ';}
$ echo "getIP eth0" > test.sh
$ sh test.sh
sh: getIP: No such file or directory
$ export -f getIP
$ sh test.sh
inet addr: 192.168.1.2 Bcast: 192.168.255.255 Mask: 255.255.0.0
读取命令返回值(状态)
命令的返回值被保存在变量$?
中
cmd;
echo $?;
返回值被称为退出状态,可用于确定命令执行成功与否,如果命令成功退出,退出状态则为0,否则为非0
#!/bin/bash
# FileName: success_test.sh
# 对命令行参数求值,比如 ls | grep txt
eval $@
if [ $? -eq 0 ];
then
echo "$CMD executed successfully"
else
echo "$CMD terminated unsuccessfully"
fi
向命令传递参数
大多数应用都能接受不同格式的参数,假设-p、-v是可用选项,-k N是另一个可以接受数字的选项,同时该命令还要求使用一个文件名作为参数,那么,它有如下几种执行方式
$ command -p -v -k 1 file
$ command -pv -k 1 file
$ command -vpk 1 file
$ command file -pvk 1
在脚本中,命令行参数可以依据其在命令行中的位置来访问,第一个参数是$1,第二个参数是$2,以此类推
# 显示出前3个命令行的参数
echo $1 $2 $3
迭代所有的命令行参数是更为常见的处理方式。shift命令可以将参数依次想做移动一个位置,让脚本能使用$1来访问每一个参数。
$ cat showArgs.sh
for i in `seq 1 $#`
do
echo $i is $1
shift
done
$ sh showArgs.sh a b c
1 ia a
2 is b
3 is c
将一个命令的输出发送给另一个命令
Unix shell脚本最棒的特性之一就是可以轻松地将多个命令组合起来生成输出。一个命令的输出可以作为另一个命令的输入
命令输入通常来自于stdin或参数。输出可以发送给stdout或stderr。当组合多个命令时,通常将stdin用于输入,stdout用于输出
在这种情况下,这些命令被称为过滤器(filter)。使用管道(pipe)连接每个过滤器,管道操作符是|
cmd1 | cmd2 | cmd3
这里组合了3个命令,cmd1的输出传递给cmd2,cmd2的输出传递给cmd3,最终来自于cmd3的输出会出现在显示器中或被导入某个文件
$ ls | cat -n > out.txt
# ls的输出被传给cat -n,后者为通过stdin所接受到的输入内容加上行号,然后将输出重定向到文件out.txt
# 1. 子shell法,将命令序列的输出赋给变量
cmd_output=$(COMMANDS)
cmd_output=$(ls | cat -n)
echo $cmd_output
# 2. 反引用法(反标记),也可以用于存储命令输出
cmd_output=`COMMANDS`
cmd_output=`ls|cat -n`
echo $cmd_output
1. 利用子shell生成一个独立的进程
子shell本身就是独立的进程,可以用()操作符来定义一个子shell
当命令在子shell中执行时,不会对当前shell造成任何影响,所有的改变仅限于子shell内
例如,当用cd命令改变子shell的当前目录时,这种变化不会反映到株shell环境中
$ pwd
/
$ (cd /bin; ls)
awk bash cat ...
$ pwd
/
2. 通过引用子shell的方式保留空格和换行符
使用子shell或反引用的方法将命令的输出保存到变量中时,为了保留输出的空格和换行符,必须使用双引号
$ cat text.txt
1
2
3
$ out=$(cat text.txt)
$ echo $out
1 2 3 # 丢失了 1 2 3 中的\n
$ out="$(cat text.txt)"
$ echo $out
1
2
3
在不按回车键的情况下读入n个字符
Bash命令read能从键盘或标注能输入中读取文本,可以使用read以交互的形式读取用户输入
# 1. 从输入中读取n个字符并存入变量variable_name
# read -n number_of_chars variable_name
$ read -n 2 var
$ echo $var
# 2. 用无显的方式读取密码
$ read -s var
# 3. 使用read显示提示信息
$ read -p "Enter input:" var
# 4. 在给定时限内读取输入
## read -t timeout var
$ read -t 2 var
# 在2秒内将键入得字符串读入变量var
# 5. 用特定的定界符作为输入行的结束
## read -d delim_char var
$ read -d ":" var
hello: # var被设置为hello