http://www.blogjava.net/liubowu/archive/2007/06/25/99317.html
\d | 本地端时间的日期 |
\l | 显示第几个终端机接口 |
\m | 显示硬件的等级 (i386/i486/i586/i686...) |
\n | 显示主机的网络名称 |
\o | 显示 domain name |
\r | 操作系统的版本 (相当于 uname -r) |
\t | 显示本地端时间的时间 |
\s | 操作系统的名称 |
\v | 操作系统的版本 |
#source ~/.bashrc #. ~/.bashrc
$PATH:决定了shell将到哪些目录中寻找命令或程序。
$HOME:当前用户主目录。
$MAIL:是指当前用户的邮件存放目录。
$SHELL:是指当前用户用的是哪种Shell。
$HISTSIZE:是指保存历史命令记录的条数。
$LOGNAME:是指当前用户的登录名。
$HOSTNAME:是指主机的名称,许多应用程序如果要用到主机名的话,通常是从这个环境变量中来取得的。
$LANG/LANGUGE:是和语言相关的环境变量,使用多种语言的用户可以修改此环境变量。
$PS1:是基本提示符,对于root用户是#,对于普通用户是$,也可以使用一些更复杂的值。
$PS2:是附属提示符,默认是“>”。
$IFS:输入域分隔符。当shell读取输入时,用来分隔单词的一组字符,它们通常是空格、制表符和换行符。
$0:shell脚本的名字。
$#:传递给脚本的参数个数。
$$:shell脚本的进程号,脚本程序通常会用它生成一个唯一的临时文件,如/tmp/tmfile_$
echo:显示指定环境变量。
export:设置新的环境变量。
env:显示所有环境变量。
set:显示所有本地定义的shell变量。
unset:清除环境变量。
将一个路径加入到PATH变量中:
如在PATH 这个变量当中“累加”一个新目录 这个目录
#1,控制台中: $ PATH="$PATH":/my_new_path" #2,修改profile文件: $ vi /etc/profile 在里面加入: export PATH="$PATH:/my_new_path" #3,修改.bashrc文件: $ vi /root/.bashrc 在里面加入: export PATH="$PATH:/my_new_path" #后两种方法一般需要重新注销系统才能生效,最后可以通过echo命令测试一
* | 代表0个或多个任意字符 |
? | 代表一定有一个任意字符 |
[ ] | [abcd],表示一个字符,或a或b或c或d |
[-] | [0-9],表示一个数字,0到9之间的某个 |
[^] | [^abc],表示一个字符,且不是a、b、c |
[root@linux ~]# ls test* #那个 * 代表后面不论接几个字符都予以接受 [root@linux ~]# ls test? #那个 ? 代表后面"一定"要接"一个"字符 [root@linux ~]# ls test??? #那个 ??? 代表"一定要接三个"字符! [root@linux ~]# cp test[1-5] /tmp # 将 test1, test2, test3, test4, test5 若存在的话,就拷贝到 /tmp [root@linux ~]# cp test[!1-5] /tmp # 只要不是 test1, test2, test3, test4, test5 之外的其它 test?拷贝到 /tmp [root@linux ~]# cd /lib/modules/`uname -r`/kernel/drivers # 系统先执行 uname -r 找出输出结果;将结果累加在目录上面,来执行 cd 的功能! = cd /lib/modules/$(uname -r)/kernel #另外,这个 quot (`) 的功能,也可以利用 $() 来取代喔! [root@linux ~]# cp *[A-Z]* /tmp #表示文件中包含大写字母 [root@linux ~]# ls -lda /etc/*[35]* #表示文件中包含数字3或者5.
# | 注释 |
\ | 转义字符 |
| | 管道(pipe) |
; | 连续命令 |
~ | 用户主文件夹 |
$ | 变量前导符 |
& | 作业控制的后台运行 |
! | 逻辑非 |
/ | 目录分隔符 |
>,>> | 数据流重定向,输出导向,分别是“替换“和”增加“ |
<,<< | 数据流重定向,输入导向 |
' ‘ | 单引号,不具有变量置换功能 |
” “ | 双引号,具有变量置换功能 |
` ` | ` `中内容可以先执行的命令,也可以用$( )来替换 |
( ) | 在中间为子shell的起始与结束 |
{ } | 在中间为命令块的组合 |
Ctrl + C | 终止目前的命令 |
Ctrl + D | 输入结束(EOF),例如邮件结束的时候; |
Ctrl + M | 就是 Enter 啦! |
Ctrl + S | 暂停屏幕的输出 |
Ctrl + Q | 恢复屏幕的输出 |
Ctrl + U | 在提示字符下,将整列命令删除 |
Ctrl + Z | 暂停目前的命令 |
0 | 标准输入 standard input |
1 | 标准输出standard output |
2 | 错误输出error output |
ls -al > newtxt #本来ls -al 命令预设输出到屏幕,现在被重新导出到newtxt文档。 ls -al >> newtxt #现将ls -al 命令输出结果“增加”到文件newtxt末尾。
$ find /home -name testing > list_right 2> list_error有 Permission 的那几行错误信息都会跑到 list_error 这个档案中,至于正确的输出数据则会存到 list_right 这个档案中。
将错误信息不要(置于垃圾箱中/dev/null) $ find /home -name testing > list_right 2> /dev/null 将正确输出和错误输出都放置到同一个文件中testing中去 $ find /home -name testing > list 2> list <==错误写法 $ find /home -name testing > list 2>&1 <==正确写法另外,这里区分一下command>file 2>file 与 command>file 2>&1:
分号; | cmd;cmd 多条命令顺序执行,执行顺序是从左到右的顺序。 |
与&& | cmd1 && cmd2 若cmd1执行完毕且正确执行($?=0),则开始执行cmd2 若cmd2执行完毕且为错误($? !=0),则cmd2不执行 |
或|| | cmd1 || cmd2 若cmd1执行完毕且正确执行($?=0),则cmd2不执行 若cmd2执行完毕且为错误($? !=0),则开始执行cmd2 |
ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe该范例总会创建/tmp/abc/hehe文件。而不是先执行后面的。
[ -f file1 ] && exit 0 || exit 1
$ sh -x ./script.sh
#!/bin/sh符号#!用来告诉系统它后面的参数是用来执行该文件的程序,在这个例子中我们使用/bin/sh来执行程序。
chmod +x filename当编辑好脚本时,如果要执行该脚本,还必须使其可执行。 这样才能用./filename 来运行。
在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。
文档可以这样写:
################################################################################### ## The script is used for the regression of lineage jar with latest hive-exec..jar ## , expression_analyze.jar, parse_common.jar, field_lineage.jar, ast_parser.jar ## in trunk. ###################################################################################区块可以这样写
############################################### ## PARAMETERS ##
2.3.1 变量类型默认为字符串类型
#!/bin/sh name="Jack" s="$name, hello!" #注意等号"="前后都不能有空格。建议字符串用双引号(单引号表示纯字符串,不支持$等)。 echo $s #输出Jack, hello!(若s用单引号,则输出$name, hello!) unset s #删除变量s
2.3.2 单引号,双引号,无引号
s="./*" echo $s #这是变量,命令即为echo ./* ,通配符解开为:./1.sh ./a ./b ./c echo '$s' #这里的单引号表示一个字符串,字符串中的$等符号不能转义,输出:$s echo "$s" #这里的双引号表示一个字符串,字符串中的$等符号要转义,其中$s为变量,所以输出./*
2.3.3 参数扩展——花括号
num=2 echo "this is the $numnd" #this is the这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以 使用花括号来告诉shell我们要打印的是num变量:
num=2 echo "this is the ${num}nd" #this is the 2nd
这将打印: this is the 2nd
${name:-default} 使用一个默认值(一般是空值)来代替那些空的或者没有赋值的变量name; ${name:=default}使用指定值来代替空的或者没有赋值的变量name; ${name:?message}如果变量为空或者未赋值,那么就会显示出错误信息并中止脚本的执行同时返回退出码1。 ${#name} 给出name的长度 ${name%word} 从name的尾部开始删除与word匹配的最小部分,然后返回剩余部分 ${name%%word} 从name的尾部开始删除与word匹配的最长部分,然后返回剩余部分 ${name#word} 从name的头部开始删除与word匹配的最小部分,然后返回剩余部分 ${name##word} 从name的头部开始删除与word匹配的最长部分,然后返回剩余部分举例如下,使用cjpeg命令将一个GIF的文件转换为JPEG的文件:
$ cjpeg image.gif > image.jpg 也许有时我们会在大量的文件上进行这样的操作.这时我们如何自动重定向?我们可以很容易的这样来做: #!/bin/sh for image in *.gif do cjpeg $image > ${image%%gif}jpg done
2.3.4 注意变量与变量字符串的问题:
read a if [ $a = "yes" ];then echo "OK" fi if [ "$a" = "yes" ];then echo "OK" fi这里$a是变量a的值,"$a"是对变量a做字符串处理结果。如果read a 时直接回车,那么$a就是空,而不是"",这时程序变成了 if [ = "yes" ]就错了,所以一般用双引号括起来,表示使用字符串值,且转义其中的$变量。
2.3.5 注意打印"*"的问题:
#!/bin/sh sql='select * from gexing;' echo $sql #其中的*会被替换成所有文件,这就相当于echo select * from table; echo "$sql" #这就相当于echo "select * from table"
names=$var_name1$var_name2 #注意,两个变量之间没有空格 sentence=${names}"hello" #直接连接
语法: declare [+/-][afrix] variable 说明: +/- "-"可用来指定变量的属性,"+"则是取消变量所设的属性。 -a 定义变量variable为数组(array)类型 -i 定义变量variable为整数(integer)类型 -r 定义变量variable为只读(readonly)类型 -x 用法与export一样,将variable设置为环境变量
示例1:让变量 sum 保存 100+300+50 的加和结果 [root@linux ~]# sum=100+300+50 [root@linux ~]# echo $sum #结果为:100+300+50 [root@linux ~]# declare -i sum=100+300+50 [root@linux ~]# echo $sum #结果为:450 示例2:生成随机数 [root@linux ~]# declare -i number=$RANDOM*10/32767 ; echo $number
foo=1 foo=$(($foo+1))
echo $ (( 13 % 3 ))
#!/bin/bash #赋值 a[0]=1 #第一种赋值方法 a[1]=2 a[2]=3 b=(6,7,8,9,10) #第二种赋值方法 #取值 echo ${b[0]} #用${数组名[下标]},下标是从0开始。下标是*或者@,则得到整个数组内容。输出6 echo ${b[*]:1:3} #直接通过${数组名[@或*]:起始位置:长度}切片原先数组,输出7 8 9 echo ${b[*]::3} #输出6 7 8(前三个元素) #遍历 echo ${b[*]} #遍历数组除用循环外还可用:“数组名[*]”或“数组名[@]”,输出6 7 8 9 10 echo ${b[@]} #输出:6 7 8 9 10 for var in ${arr[@]};do echo $var; done #分行输出:6 7 8 9 10 #数组个数 echo ${#b[*]} #输出:5 echo ${#b[@]} #输出:5 #修改和删除 b[0]=0 #修改:重新赋值 echo ${b[*]} #输出:0 7 8 9 10 unset b[0] #删除:删除第一个元素 echo ${b[*]} #输出:7 8 9 10
{...}
$* 为"1 2 3"(在一个变量中列出所有参数,各个参数之间用环境变量IFS中的第一个字符分隔开,所以如果IFS置空,则会变成"123") $@ 为"1 2 3"($*的变体,不适用环境变量IFS,而是以空格连接参数,所以当IFS置空,则扔为"1 2 3") $# 为3(参数数量) $0 $n,用来存放函数调用或脚本执行时传入的参数,$0为test.sh $1 为1,以此类推 $$ 脚本运行的当前进程的ID号 $! 后台运行的最后一个进程的ID号 $- 显示shell使用的当前选项 $? 显示最后命令的退出状态,0表示无错误(这个变量也常常用来打印输出,在脚本调试时标记某个shell命令或某个函数是否正确执行,但是要注意,$?记载的是最近的函数或命令的退出状态,因此打印时应该立即打印以获得正确的信息)
[root@linux ~]# read [-pt] variable参数:
[root@linux ~]# read -p "Please keyin your name: " -t 30 name Please keyin your name: VBird Tsai [root@linux ~]# echo $name VBird Tsai
echo -e hello,"/n"world!
设置颜色
设置彩色文本 重置=0 黑色=30 红色=31 绿色=32... echo -e "\e[1;31m This is red text \e[0m" 设置彩色背景 重置=0 黑色=40 红色=41 绿色=42... echo -e "\e[1;42m This is green background \e[0m"
注意:如果alias ls = 'ls --color' 这时候 ls | xargs tar -czvf 1.tar.gz会出现以上类似的错误tar: \033[00mxy_psp_proto.h\033[00m: Cannot stat: No such file or directory
用echo -n 去掉末尾的换行符。
echo -n "string to output"
输出命令printf(默认无换行符)
printf "hello"
#!/bin/sh # we have less than 3 arguments. Print the help text: if [ $# -lt 3 ] ; then cat << EOF [批量换名:对文件名进行批量替换] USAGE: ren 'regexp' 'replacement' files... EXAMPLE: rename all *.HTM files in *.html: sh $0 'HTM$' 'html' *.HTM HELP EOF exit 0 fi OLD="$1" NEW="$2" # The shift command removes one argument from the list of # command line arguments. shift shift # $* contains now all the files: for file in $*; do if [ -f "$file" ] ; then #这里的|是管道,将源文件名进行词汇替换 newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` if [ -f "$newfile" ]; then echo "ERROR: $newfile exists already" else echo "renaming $file to $newfile ." mv "$file" "$newfile" fi fi done分析:
这是一个复杂一些的例子。让我们详细讨论一下。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。 如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从 参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我 们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目 的:得到了旧文件名和新文件名。然后使用mv命令进行重命名。
test expression其中条件expression是一个表达式,该表达式可由数字、字符串、文本和文件属性的比较,同时可加入各种算术、字符串、文本等运算符。
[ expression ]其中“[ ”是启动测试的命令,但要求在expression后要有一个“ ]”与其配对。使用该命令时要特别注意“[”后和“]”前的空格是必不可少的。
ls | grep "core"2,使用反斜线
tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`3,使用$()
more $(grep -l POSIX *)
常用命令语法及功能
echo "some text" | 将文字内容打印在屏幕上 |
ls | 文件列表 |
wc –l file wc -w file wc -c file |
计算文件行数 计算文件中的单词数 计算文件中的字符数 |
cp sourcefile destfile | 文件拷贝 |
mv oldname newname | 重命名文件或移动文件 |
rm file | 删除文件 |
grep 'pattern' file | 在文件内搜索字符串比如:grep 'abc' 1.txt |
cut -b colnum file | 指定欲显示的文件内容范围,并将它们输出到标准输出设备 比如:输出每行第5个到第9个字符cut -b5-9 file.txt 千万不要和cat命令混淆,这是两个完全不同的命令 |
cat file.txt | 输出文件内容到标准输出设备(屏幕)上 |
file somefile | 得到文件类型 |
read var | 提示用户输入,并将输入赋值给变量 |
sort file.txt | 对file.txt文件中的行进行排序 |
uniq | 删除文本文件中出现的行列 比如: sort file.txt | uniq |
expr | 进行数学运算Example: add 2 and 3expr 2 "+" 3 |
find | 搜索文件 比如:根据文件名搜索find . -name filename -print |
tee | 将数据输出到标准输出设备(屏幕) 和文件 比如:somecommand | tee outfile |
basename file | 返回不包含路径的文件名 比如: basename /bin/tux将返回 tux |
dirname file | 返回文件所在路径 比如:dirname /bin/tux将返回 /bin |
head file tail file |
打印文本文件开头几行 打印文本文件末尾几行 |
sed | Sed是一个基本的查找替换程序。 |
awk | awk 用来从文本文件中提取字段。 |
if ....; then .... elif ....; then .... else .... fi大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等…
通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。
[ ! -d $CASE ] && echo "No case path $CASE, quit!" && exit 1 #判断如果没有目录$CASE就退出[ -f "somefile" ] :判断是否是一个文件
直接执行以下脚本:
#!/bin/sh if [ "$SHELL" = "/bin/bash" ]; then echo "your login shell is the bash (bourne again shell)" else echo "your login shell is not bash but $SHELL" fi
变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。
快捷操作符可用的。这里有个例子:
#!/bin/sh mailfolder=./lineage_case [ ! -r "$mailfolder" ]&&{ echo "Can not read $mailfolder" ; exit 1; } dir="${mailfolder}/*" #grep "^From" `echo "$dir"` # grep "^From" $dir #这两者效果相同,关键在于要知道这里的*要表达的是真正的*,还是表示通配,这里表示通配 sql="select * from table;" echo "$sql" #这里要表达的是真正的*,而不是通配
该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。{}构成匿名函数。
case ... in ...) do something here ;; esac让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:
#!/bin/sh ftype=`file "$1"` case "$ftype" in "$1: Zip archive"*) unzip "$1" ;; "$1: gzip compressed"*) gunzip "$1" ;; "$1: bzip2 compressed"*) bunzip2 "$1" ;; *) echo "File $1 can not be uncompressed with smartzip";; esac您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。也就是说,当我们运行:
再看一例
#!/bin/sh echo “Is it morning? Please answer yes or no” read timeofday case “$timeofday” in [yY] | [Yy][Ee][Ss]) echo “Good Morning”;; [nN]*) echo “Good Afternoon”;; *) echo “Sorry, answer not recognized” exit 1 ;; esac exit 0
select var in ... ; do break done .... now $var can be used ....下面是一个例子:
#!/bin/sh echo "What is your favourite OS?" select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do break done echo "You have selected $var"下面是该脚本运行的结果:
What is your favourite OS? 1) Linux 2) Gnu Hurd 3) Free BSD 4) Other #? 1 You have selected Linux
while表达式: while ...; do .... done
while-loop 将运行直到表达式测试为真。关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。
例如:
#!/bin/sh i=1 while [ "$i" -le 10 ];do echo "num is $i" i=$((i+1)) done或:
#!/bin/sh i=1 while [ "$i" -le 10 ] do echo "num is $i" i=$((i+1)) done
until 条件 do 语句 done
以下代码直到有内容时返回值才为0,因此跳过do|done,然后输出echo。其中的>/dev/null只是为了将结果不在屏幕显示,不影响返回值。
until who | grep "$1" > /dev/null do sleep(60) done echo "$1 has logged in"
for var in ....; do .... done在下面的例子中,将分别打印ABC到屏幕上:
#!/bin/sh for var in A B C ; do echo "var is $var" done下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:
#!/bin/sh # list a content summary of a number of RPM packages # USAGE: showrpm rpmfile1 rpmfile2 ... # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm for rpmpackage in $*; do if [ -r "$rpmpackage" ];then echo "=============== $rpmpackage ==============" rpm -qi -p $rpmpackage else echo "ERROR: cannot read file $rpmpackage" fi done这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。
for的另一种用法:
for (( 初始值; 限制值; 执行步长 )) do 程序段 done
例如:
#!/bin/bash # Program: # Try do calculate 1+2+....+${your_input} # History: # 2005/08/29 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH read -p "Please input a number, I will count for 1+2+...+your_input: " nu s=0 for (( i=1; i<=$nu; i=i+1 )) do s=$(($s+$i)) done echo "The result of '1+2+3+...+$nu' is ==> $s"
break
continue
通常,当一个脚本执行一条外部命令或者脚本程序时,它会创建一个新的环境,也就是一个子shell,命令将在这个新环境中执行,在执行完毕后,这个环境被丢弃,留下退出码返回给父shell。但是外部的source命令和点命令在执行脚本程序中列出的命令时,使用的是调用该脚本程序的同一个shell。source命令或dot命令将外部命令放在当前进程(而不是子进程)环境中运行(类似c语言中的 #include语句),并继承当前进程(shell)的所有变量。
范例:用dot命令修改当前进程的环境变量
以下是文件classic_set (当前目录下)的内容:
version=classic PATH=/usr/local/old_bin:/usr/bin:/bin:. PS1=“classic>”以下是文件latest_set (当前目录下)的内容:
version= latest PATH=/usr/local/new_bin:/usr/bin:/bin:. PS1=“latest >”用dot 命令执行这两个shell脚本:
$ . ./classic_set classic> echo $version classic classic> . latest_set latest > echo $version latest latest >
在默认情况下,在一个shell里创建的变量在此shell调用的下级(子)shell里是不可用的。
export命令将作为它参数的变量导出到子shell中,并使之在子shell中有效,一旦一个变量被shell到处,它就可以被该shell调用的任何脚本使用,也可以被后续依次调用的任何shell使用。
将当前的shell替换为一个不同的程序,wall会替换整个脚本,然后原脚本exec语句后面的脚本内容都不会再继续运行。
... exec wall "that's all,we will finish now" ...
#!/bin/sh while [ "$1" != "" ];do echo "$1" shift done exit 0
trap命令用来指定在接收到操作系统信号之后将要采取的行动。脚本程序通常是从头到尾解释并运行的,所以必须把trap命令放在准备保护的脚本程序部分之前。
trap命令常见的用途在于脚本程序中断时完成清理工作,比如临时文件等。例子程序如下:
#!/bin/sh trap 'rm -f /tmp/my_tmp_file_$$' INT echo creating file /tmp/my_tmp_file_$$ date > /tmp/my_tmp_file_$$ echo "press interrupt (CTRL-C) to interrupt ......" while [ -f /tmp/my_tmp_file_$$ ]; do echo File exists sleep 3 done echo we never get here exit 0
在这个脚本程序里,先用trap命令安排它在出现INT(中断)信号时执行“rm -f /tmp/my_tmp_file_$$”命令删除临时文件。然后让脚本程序进入一个while循环,在临时文件存在的情况下不断循环。当用户按下CTRL-C组合键时,语句rm -f /tmp/my_tmp_file_$$ 就会被执行,然后继续下一个循环。但是因为临时文件已经被删除了,所以while循环在第一次执行时就会正常退出。注:$$表示当前的shell进程号。运行该脚本,首先在tmp下创建临时文件my_tmp_file_$$,如果遇到INT中断,即Ctrl+c,即删除该文件。
使用后台运行的方式 & 以及wait函数来控制多进程步骤
#!/bin/bash sh aa.sh sh bb.sh & p1=$! sh cc.sh & p2=$! wait $p1 && wait $p2
[ function ] funname [()] { action; [return int;] }
说明:
1、可以带function f() 定义,也可以直接f() 定义,不带任何参数。
2、函数的参数默认保存在$1,$2,...中,$0中保存函数名。
3、函数的返回值默认是最后一条命令的运行结果,除非显示有return n(0-255)。返回值由$?获取。
4、先定义后使用。
其一,函数内部使用 return 这个命令,出函数后立刻用$?访问,return只能返回非负数整数 且超过255的会反卷,也就是256就会变成0。
即函数内部:return,函数外部:echo $?
#!bin/sh function sum() { return $(($1+$2)) } sum 1 2 echo $?
其二,函数内部使用echo这个命令输出想要返回的值,同时调用函数的时候把函数的执行结果赋值给一个变量,那么这个变量里才是真正想要的返回值。
即函数内部 echo,函数外部:c = $( sum 1 2)
#!bin/sh function sum() { echo $(($1+$2)) } c=$(sum 1 2) echo $c
#!bin/sh function sum() { echo $(($1+$2)) return $(($1-$2)) } sum $1 $2 #这里因为调用函数,所以输出5+2=7 c=$(sum $1 $2) #这里调用函数被当做一条命令,因此其中的echo不起作用,因此只将函数体内最后一条语句的结果(而非返回值)保存在c中,即echo的结果。5+2=7. echo $? #这是上一个函数调用的返回值,为3,(这里用$?,所以函数内部找return) echo $c #这里用$c,所以函数内部找echo运行结果:
$ . 1.sh 5 2 7 3 7c=$(sum $1 $2); 在shell中,但括号里是命令语句。 因此,我们可以将shell中函数,看作是定义一个新的命令。
范例:下面是一个叫做xtitlebar的脚本,使用这个脚本您可以改变终端窗口的名称。这里使用了一个叫做help的函数。正如您可以看到的那样,这个定义的函数被使用了两次。
#!/bin/sh # vim: set sw=4 ts=4 et: help() { cat <<EOF xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole USAGE: xtitlebar [-h] "string_for_titelbar" OPTIONS: -h help text EXAMPLE: xtitlebar "cvs" HELP EOF exit 0 } # in case of error or if -h is given we call the function help: [ -z "$1" ] && help [ "$1" = "-h" ] && help # send the escape sequence to change the xterm titelbar: echo -e "33]0;$107"
#!/bin/sh help() { cat <<EOF This is a generic command line parser demo. USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2 HELP EOF exit 0 } while [ -n "$1" ]; do case $1 in -h) help;shift 1;; # function help is called -f) opt_f=1;shift 1;; # variable opt_f is set -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2 --) shift;break;; # end of options -*) echo "error: no such option $1. -h for help";exit 1;; *) break;; esac done命令:
原理:
这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数.
################################################################################### ## The script is used for the test of ABC.jar in myApps ## @author:xing.gexing ## @date 2012-10-26 下午4:05:07 ## @version V1.0 ################################################################################### ############################################### ## PARAMETERS ## SMOKE='true' SMOKE_MAILTO='xing.gexing\@xxx.com' MAILTO='xing.gexing\@xxx.com' WHITE_LIST='white.list' DIR='/home/admin' WORKSPACE="${DIR}/myApps" [ ! -d $WORKSPACE ] && echo "No case path $WORKSPACE, quit!" && exit 1 ############################################## ## BUILD ABC.jar ## SOURCE="$WORKSPACE/source" DEST="$WORKSPACE/dest" cd $TRUNK svn up --username=xxx --password=ooo [ $? -ne 0 ] && echo "svn up failed!!! quit!" && exit 1 ant clean && ant package [ $? -ne 0 ] && echo "build ABC.jar failed!!! quit!" && exit 1 cp $TRUNK/build/dist/*.jar $DEST/lib [ "$SMOKE" == 'true' ] && MAILTO=$SMOKE_MAILTO && WHITE_LIST=$WORKSPACE/white.list sed -i "s@#MAIL_TO#@$MAILTO@" $ENV_CFG sed -i "s@#WHITE_LIST#@$WHITE_LIST@" $ENV_CFG sed -i "s@#TRUNK_PATH#@$WORKSPACE@" $ENV_CFG ############################################### ## run ## python test.py -abcd
#!/bin/sh ############################################## #Author GE Xing #Time 2013 05 16 ############################################## # column title # echo -e "Reduce, jvm start, reduce done, reduce duration, write size, writing start, writing end, writing duration, real writing start, real writing end, real writing duration" for line in `cat "./ids.result"` do ############################################## ## task_name(REDUCE) ## reduce_name=$line #echo ----reduce_name: echo -e "${reduce_name}, \c" ############################################## ## jvm start time ## jvm_start=`cat mapAndReduce.result| grep $reduce_name | grep "given task" | awk '{print $1, $2}'` #time_jvm_start=`date -d "$jvm_start" +%s` time_jvm_start=$(transTime "$jvm_start") #echo ----jvm_start: echo -e "${time_jvm_start}, \c" ############################################## ## reduce done ## reduce_done=`cat mapAndReduce.result| grep $reduce_name | grep " is in commit-pending, task state:" | awk '{print $1, $2}'` time_reduce_done=$(transTime "$reduce_done") #echo ----reduce_done: echo -e "${time_reduce_done}, \c" ############################################## ## reduce duration ## reduce_duration=`expr $time_reduce_done - $time_jvm_start` #echo ----reduce_duration: echo -e "${reduce_duration}, \c" ############################################## ## write size ## write_size=`cat mapAndReduce.result| grep $reduce_name | grep "op: HDFS_WRITE, cliID:" | awk 'NR==1 {print $10}'` #echo ----write_size: echo -e "${write_size} \c" ############################################## ## writing start time ## writing_start=`cat mapAndReduce.result| grep $reduce_name | grep "NameSystem.allocateBlock" | awk '{print $1, $2}'` time_writing_start=$(transTime "$writing_start") #echo ----writing_start: echo -e "${time_writing_start}, \c" ############################################## ## writing end time ## writing_end=`cat mapAndReduce.result| grep $reduce_name | grep "Removing lease on file" | awk '{print $1, $2}'` time_writing_end=$(transTime "$writing_end") #echo ----writing_end: echo -e "${time_writing_end}, \c" ############################################## ## writing duration ## writing_duration=`expr $time_writing_end - $time_writing_start` #echo ----writing_duration: echo -e "${writing_duration}, \c" ############################################## ## real writing start time ## T=`cat mapAndReduce.result| grep $reduce_name | grep "op: HDFS_WRITE, cliID:" | awk '{print $1, $2, $22}'` #echo -e "T $T\n" t1=`echo $T |awk '{print $1, $2}'` #echo -e "t1 $t1\n" r1=$(transTime "$t1") #echo -e "r1 $r1\n" d1=`echo $T |awk '{print $3/1000}'` #echo -e "d1 $d1\n" b1=`expr $r1 - $d1` #echo -e "b1 $b1\n" #t2=`echo $T |awk '{print $4, $5}'` #r2=`date -d "$t2" +%s` #d2=`echo $T |awk '{print $6}'` #b2=`expr $r2 - $d2` # #t3=`echo $T |awk '{print $7, $8}'` #r3=`date -d "$t3" +%s` #d3=`echo $T |awk '{print $9}'` #b3=`expr $r3 - $d3` # #min=$b1 #if test $b2 -lt $min # then # min=$b2 #fi #if test $b3 -lt $min # then # min=$b3 #fi # #max=$b1 #if test $b2 -gt $max # then # max=$b2 #fi #if test $b3 -gt $max # then # max=$b3 #fi real_writing_start=$b1 #echo ----real_writing_start: echo -e "${real_writing_start}, \c" ############################################## ## real_writing end time ## real_writing_end=$r1 #echo ----real_writing_end: echo -e "${real_writing_end}, \c" ############################################## ## real_writing duration ## #real_time_writing_start=`date -d "$real_writing_start" +%s` #real_time_writing_end=`date -d "$real_writing_end" +%s` #real_writing_duration=`expr $real_time_writing_end - $real_time_writing_start` real_writing_duration=`expr $real_writing_end - $real_writing_start` #echo ----real_writing_duration: echo -e "${real_writing_duration}" done function transTime { echo "$1" | awk -F'[:, ]' '{print ($4+$3*60+$2*60*60)*1000+$5}' }
bash -v sum.sh表示将代码执行之前,先将代码显示出来
[gexing111@gexing111 myapps]$ bash -v sum.sh
#!/bin/bashNO
bash -v sum.sh表示将代码执行过程中显示出来
NO
程序1:Hello.sh
#!/bin/bash clear echo "Welcome to my first Linux Program!" echo "Enter your name :" read response echo "Hello,$response!"
程序2:readEmployees.sh
#!/bin/bash clear echo "Plz input your Name" read Name echo "Plz input your Age" read Age echo "Name:$Name Age:$Age">>mydata.dat echo "" echo "Employees:" echo "" cat mydata.dat
程序3:sum.sh
#!/bin/bash let a=30 let b=20 let sum="$a + $b" if test $a -lt $b then echo "OK" else echo "NO" fi
程序4:mymenu.sh
#!/bin/bash declare flag="1" while [ $flag -eq "1" ] do echo "The Telephone Book" echo "" echo "1.Display A Telephone Number" echo "2.Add A New Telephone NUmber" echo "" echo "Q Quit" echo "" echo "Enter your selection:" read selection case $selection in "1") echo "You want to display a telephone number." getnum ;; "2") echo "You want to add a new telephone number." addnum ;; "q") flag="0" ;; "Q") flag="0" ;; *) echo "You made an invalid selection." esac done5,程序friends.sh
#!/bin/bash for friend in "Mary Jones" "Joe Smith" "Sue Jones" do echo "Hello,$friend" done6,程序raining.sh
#!/bin/bash declare raining="1" while [ $raining -eq "1" ] do clear echo "" echo "Is it raining?" echo "" echo "1,YES" echo "2,NO" echo "" echo "Enter your selection:" read raining done echo "It stopped raining."
#!/bin/bash clear declare count1=1 declare count2 while [ $count1 -lt 6 ] do echo "Warning:There is a bug in your program!" let count2=1 while [ $count2 -lt 20000 ] do let count2="$count2 + 1" done clear let count2=1 while [ $count2 -lt 20000 ] do let count2="$count2 + 1" done let count1="$count1 + 1" done
#!/bin/bash let n=1 while [ $n -eq 1 ] do echo "Enter your name or \"stop\" to end:" read name case $name in "stop") echo "Bye!" break ;; *) echo "Hi,$name!" ;; esac done
#!/bin/bash clear function display { echo "Welcome to the world" echo "of functions." } display
#!/bin/bash clear function verify { if [ $# -ne 2 ] then echo "Wrong number of arguments!" #字符串的比较用= 而数字的比较用-eq elif [ $1 = "gexing111" ] && [ $2 = "111gexing" ] then echo "Verified" else echo "Rejected" fi } verify $1 $2