Shell编程注意点 ( by quqi99 )
来源:互联网 发布:java path类 编辑:程序博客网 时间:2024/06/11 16:45
Shell编程注意点 ( by quqi99 )
作者:张华 写于:发表于:2011-04-06
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明
( http://blog.csdn.net/quqi99 )
1在shell脚本中调用另一个脚本的三种不同方式(fork,exec, source)
我们先谈谈在shell脚本中调用另一个脚本的三种不同方式的区别(fork,exec, source )
fork ( /directory/script.sh ), fork是最普通的,就是直接在脚本里面用/directory/script.sh来调用script.sh这个脚本.运行的时候开一个sub-shell执行调用的脚本,sub-shell执行的时候,parent-shell还在。sub-shell执行完毕后返回parent-shell.sub-shell从parent-shell继承环境变量.但是sub-shell中的环境变量不会带回parent-shell
exec(exec /directory/script.sh) exec与fork不同,不需要新开一个sub-shell来执行被调用的脚本. 被调用的脚本与父脚本在同一个shell内执行。但是使用exec调用一个新脚本以后,父脚本中exec行之后的内容就不会再执行了。这是exec和source的区别
source(source/directory/script.sh)与fork的区别是不新开一个sub-shell来执行被调用的脚本,而是在同一个shell中执行.所以被调用的脚本中声明的变量和环境变量,都可以在主脚本中得到和使用.
可以通过下面这两个脚本来体会三种调用方式的不同:
1.sh
#!/bin/bash
A=B
echo "PID for 1.sh before exec/source/fork:$$"
exportA
echo "1.sh: /$A is $A"
case $1 in
exec)
echo "using exec…"
exec ./2.sh ;;
source)
echo "using source…"
../2.sh ;;
*)
echo"using fork by default…"
./2.sh ;;
esac
echo"PID for 1.sh after exec/source/fork:$$"
echo "1.sh:/$A is $A"
2.sh
#!/bin/bash
echo"PID for 2.sh: $$"
echo "2.sh get /$A=$A from1.sh"
A=C
export A
echo "2.sh: /$A is $A"
执行情况:
$./1.sh
PID for 1.sh beforeexec/source/fork:5845364
1.sh: $A is B
using fork bydefault…
PID for 2.sh: 5242940
2.sh get $A=B from 1.sh
2.sh:$A is C
PID for 1.sh after exec/source/fork:5845364
1.sh: $A isB
$ ./1.sh exec
PID for 1.sh beforeexec/source/fork:5562668
1.sh: $A is B
using exec…
PID for2.sh: 5562668
2.sh get $A=B from 1.sh
2.sh: $A is C
$./1.sh source
PID for 1.sh beforeexec/source/fork:5156894
1.sh: $A is B
using source…
PIDfor 2.sh: 5156894
2.sh get $A=B from 1.sh
2.sh: $A is C
PIDfor 1.sh after exec/source/fork:5156894
1.sh: $A is C
$
2函数调用
先看一个例子,执行mysql的函数mysqlExec,如下:
source“mysql.conf”
mysqlExec(){sql=$1
sqlOp=`echo${sql:0:6}| tr A-Z a-z`
if[ "$sqlOp" != "select" ]; then
sql=$sql";select row_count();"
fi
#use different mysql command depends on the password
if[ -z $MYSQL_PASSWORD ]
then
$mysql $MYSQL_DATABASE -h$MYSQL_HOSTNAME -u$MYSQL_USERNAME -se "${sql};"
else
$mysql $MYSQL_DATABASE -h$MYSQL_HOSTNAME -u$MYSQL_USERNAME -p$MYSQL_PASSWORD-se "${sql};"
fi
status=$?
if[ $status -eq 0 ]; then
if[ "$sqlOp" != "select" ]; then
log "OK $sql"
fi
else
log "Occur DB Error, can retry in 3 seconds later -> $sql"
sleep3
echo "DB_ERROR"
fi
return $status
exit
}
函数调用要注意两点:
1)函数中可以用echo,如上面的echo "DB_ERROR",在调用时要获取echo的值,应该这样:
campaign=`mysqlExec"$sql"`
if[ "x$campaign" == "x" -o "$campaign" =="DB_ERROR" ]; then
continue
fi
2)函数中也可以有返回值,如上面的return $status,在调用时应该通过$?获得,如:
if[ $? -eq 0 ]; then
echo“zhanghua”
fi
3) 如果想从被调用的函数处返回一个值,可以这样
调用gen_conf函数,传一个引用(注意不是变量)config_file进去, gen_conf $host config_file
在gen_conf函数中通过__resultvar变量返回值:
gen_config{
local __resultvar=$2
eval $__resultvar="'$config'"}
3shell中的要用局部变量很纠结
你会看到shell有一个非常大的缺点,就是它在函数调用时,没有局部变量与全局变量之分,如A脚本调用B脚本中的一个函数,在B脚本内部有一个变量vari(你可能受JAVA影响认为它是局部变量那就大错特错了),如果A脚本中也有这个名为vari的变量,那么在函数返回时,B脚本的那个vari变量会将A脚本的vari变量覆盖,举个例子:
updateWithOptimisticLock(){
rand=$1
campaignId=$2
seq=1
updateVal=-1
status=1
while[ true ]; do
if[ $seq -gt 3 ]; then
log"FATAL ERROR, Update num error, $updatesql"
break
fi
cur=`queryCur"$campaignId"`
if[ "$cur" == "DB_ERROR" ]; then
continue
fi
updateVal=$(($cur+$rand))
if[ "$rand" == "0" ]; then
break
fi
updatesql="updatet_campaign_ set num=$updateVal where campaign_id=$campaignId andnum=$cur"
affectRows=`mysqlExec"$updatesql"`
if[ "$affectRows" == "1" ]; then
status=0
break
fi
seq=$(($seq+1))
done
echo$updateVal
return$status
}
调用的伪码如下,这时里面的seq变量会被上述updateWithOptimisticLock函数中的变量seq给覆盖,所以在shell中没有局部变量一说
seq=1
while[ $seq -le $cycleNum ]; do
updateFakeNumWithOptimisticLock$rand $campaignId
done
4使用xargs来传参数
在shell中的管道符|很强大,可以将前一条命令的标准输出作为下一条命令的标准输入,但是如果下一条命令不是标准输入而是需要传参的话,那怎么办呢,用xargs即可,例如下列shell中xargs命令的-i选项告诉xargs用前一条命令的标准输出去替换{}。
find. | xargs zgrep "<URL>/Search?" | sed's/.*q=/([-_*()~.%+0-9A-Za-z]*/).*//1/' | sort -nr | uniq -c | sort-nr | head -1000 | xargs -i php -r "echorawurldecode('{}')./"/n/";" > result.out &
当然exec也可以实现上述功能,只是exec都是一次性读入内存容易内存溢出,如:
find. -name "*.m4" -exec grep --color -H "catalina"{} /;
5shell中的sed命令使用的正则是缩水版
shell中的sed命令使用的正则引擎和我们java中平常所用正则引擎并不一样,功能比较弱。
如上节中的|sed 's/.*q=/([-_*()~.%+0-9A-Za-z]*/),就是因为shell的很多正则不支持,才在使用sed命令时用了那么多枚举。
nova service-list --bi nova-compute | grep nova-compute | cut -d ' ' -f 4 | xargs -n 1 -I {} ssh -o StrictHostKeyChecking=no ubuntu@{} "date; hostname; zgrep MessagingTimeout /var/log/nova/nova-compute.log*; echo -e '-----------------------------\n'"
- Shell编程注意点 ( by quqi99 )
- shell编程注意点
- shell编程注意点
- shell EOF注意点
- shell相关注意点
- linux shell注意点
- linux shell 编程常需要的注意点 (一)
- shell编程关于程序调试一些注意点
- socket编程注意点
- 编程中的注意点
- 网络编程注意点
- C++编程注意点
- 网络编程 注意点
- 编程注意点
- 多线程编程注意点
- php编程注意点
- shell注意点(一)
- shell注意点(二)
- AndroidManifest.xml分析
- 邓聿文:保障房建设要防止"尺蠖效应"
- maillist of Hacking USB@LINUX
- 金额转换
- forward sendRedirect 区别
- Shell编程注意点 ( by quqi99 )
- cvs no such repository 问题
- 在分类页面下得到当前目录下的所有子目录,并输出! ---当前分类下的所有子分类!
- MemCached 学习笔记
- tomcat多域名配置
- 如何使用CInternetSession打开https网站
- rabbitmq源码分析(一)
- C语言谜题
- IE浏览器中iframe背景透明