linux shell编程控制结构:expr、let、for、while、until、shift、if、case、break、continue、函数、select 学习笔记
分类: linux2013-06-05 15:49 223人阅读 评论(0) 收藏 举报
Linux
SHELL编程一UNIX和Shell工具简介
什么是shell?
shell只是一个程序,它在系统中没有特权。因此,有多个不同风格shell共同存在原因——Bourne Shell,Korn Shell,C Shell。
在shell输入命令,先分析用户键入的每个命令,然后为执行程序作初始化。
Shell有自己的内部程序设计语言,这种语言是解释型的,shell用这种语言解释命令行的每一条语句,然后执行。
C等编译型语言,一般是先编译成可执行文件再执行。
1)正规表达式
. 匹配任意字符
ed files, ed 编辑命令
^contents 匹配行首符号
contents$ 匹配文件尾
[...] 匹配[]内的字符之一
{...}:x{...}匹配精确数目的字符串
...: 保存匹配的字符串
2)cut
cut -cN file
cut -dchar -fN file
char是分割符
N 从第1 个开始数的第N 个字节、字符或域
N- 从第N 个开始到所在行结束的所有字符、字节或域
N-M 从第N 个开始到第M 个之间(包括第M 个)的所有字符、字节或域
-M 从第1 个开始到第M 个之间(包括第M 个)的所有字符、字节或域
3)paste命令
paste file1 file2 file3 ,将三个文件的内容连接起来,直接在对应的每一行后连接而不是在第一个文件末尾连接
paste -d‘char’ file1,file2
-d是 可选参数,文件连接的时候的默认分隔符是制表符,我们可以用-d来设定我们想要的字符,其中char的单引号最好是有,没大部分情况也是行的。
paste -d'char' -s file,-s告诉paste把同一个文件file的行用char连在一起
4)sed 用来编辑数据的程序,指的是流编辑器,与ed的区别是其不能用于交互
sed 's/char1/char2/d' file,将file里面的每一个char1替换成char2,只有s的话只会将每行的第一个char2替换,加上g会将所有的char2替换
sed -n '1,2p' file,选项-n表示没有显式要求的话不显示任意一行,显式指定用p命令来实现,该命令表示输出file的1-2行
sed -n '/char/p' file,显示包含单词char的行
sed ‘1,2d’file,删除file文件的1-2行
5)tr 过滤器tr用于转换来自标准输入的字符
tr from-chars to-chars,from-chars 和to-chars都是一个或多个字符,输入的任意在from-chars的字符转换成to-chars中的字符
tr a b < file, 将file中的a全部转成b
tr '[a-z]' '[A-Z]' < file, 小写都换成大写
tr -s ':' ' ' < file,假设有连续的多个:,假如没有-s,那么出来的结果将会是压缩成一个' '。
tr -d ':' < file ,删除输入流中的:
6)grep 可以搜索一个或多个文件中特定的字符串模式
grep char files
grep -v char file 显示不包含char的行
grep -l char * ,显示包含char的文件名
grep -n char file, 显示行号
7)sort 对输入文件的每一行排序,默认升序
-u 去掉重复行
-r 降序排列
-o,输出重定向,跟>很像,区别在于-o可以重定向为同一个文件,而>不行
-n,按算术方法排序
8)uniq 查找并消除连续重复行
uniq file1
uniq file1 file2
uniq file -d,输出连续重复的行
uniq file -c,输出每行出现的次数
一、基础知识
Shell提供一个到UNIX系统的接口,它收集用户输入并根据输入执行程序,并显示程序的输出。有时被叫做命令解释器。
1、命令:简单命令、复杂命令(带参数)、复合命令(分号隔开,如:who; ll)。
2、Shell类型:Bourne Shell(包括sh, ksh, bash)和C Shell(包括csh, tcsh)。
3、模式:交互式和非交互式。
交互式启动:$/bin/sh 退出:exit
非交互式启动:$/bin/sh filename
4、初始化文件 /etc/profile
使用的终端类型:TERM=vt100
定位命令列表:PATH=/bin:/usr/bin
定位命令帮助列表:MANPATH=/usr/man:/usr/share/man
5、执行 chmod a+x ./logins 例,内容为:
#!/bin/sh 位于第一行,而在其他行时#开头为注
who;ls;
6、文件操作:
ls –aF; cat filename; wc filename; cp -i source destination;
mv –i source destination; rm files;
7、目录操作:
pwd; cd directory; mkdir directory; cp - r source destination;
mv source destination; rmdir; rm –r;
8、文件属性操作:
符号链(相当于快捷方式或别名)创建:ln –s source destination
管道
chmod expression files; (r,w,x,o; 4读,2写,1执行)
chown改变一个文件的所有权; chown options user:group files
chgrp options group files
9、进程
前台进程,后台进程。启动后台进程在命令后面添加&。
前移后:ctrl+z. 后移前:fg. 使后台进程持续运行:nohup
jobs(显示悬挂的及正在后台运行的进程) ps(正在运行的所有进程) kill
SHELL编程二
二、编程
1、变量
定义:name=value (使用带空格的值时加引号)
访问:$name
例:FRUIT=apple $echo $FRUIT(结果为apple) $echo FRUIT(结果为FRUIT)
Bourne Shell只支持标量,Korn Shell中支持数组。
数组创建: name[index]=value 数组访问:${name[index]}
只读变量:readonly name
删除变量:unset name
局部变量(只在当前SHELL实例中存在),环境变量(SHELL任何子进程都能使用),SHELL变量(正确运行所必需,如PWD,PATH,HOME等)。
导出环境变量:export name
2、替换
(1)文件名替换通配符:*(匹配0个或多个)、?(匹配1个存在的任何字符)、[characters]。
匹配给出的字符,例ls test[0123456789].sql或ls test[0-9].sql 。匹配所有以字母或数字结尾的文件:ls *[a-z A-Z 0-9]。
否定一个集合:如列出所有除a开头的文件,ls [!a]*。
(2)变量替换:
${parameter:-word} 若parameter为空或未设置,则用word代替,parameter值不变
${parameter:=word} 若parameter为空或未设置,则parameter设为值word
${parameter:?message} 若parameter为空或未设置,则message作为标准错误打印
${parameter:+word} 若parameter设置了,则用word代替,parameter值不变
(3)命令和算术替换
例:DATE=’date’ UP=’date; uptime’
foo:$((5+3)/2)
3、引用:关掉一个字符的特殊意义。
三种方式:/(关掉某个),’(关掉全部),”(关掉部份)。
例:echo Hello /; world 输出 Hello ; world
echo ‘<125.**>;(update)’ 输出<125.**>;(update)
双引号未关掉:$用于参数替换,后引号 ’用于命令替换,”, /。
4、流控制
(1)if语法:if list1
then list2
elif list3
then list4
else list5
fi
其中elif和else可选。
例:#!/bin/sh
Fruit=apple
F=b
if $Fruit>$F;
then echo $Fruit
else echo $F
fi
使用test:test expression,可用文件测试、字符串比较、数字比较。
(2)case语法:case word in
pattern1) list1 ;;
Pattern2) list2 ;;
esac
其中;;类似于break。
例:#!/bin/sh
Fruit=apple
case “$Fruit” in
apple) echo “I like apple.” ;;
banana) echo “banana” ;;
esac
运行后输出I like apple.
条件可以运前之前学习的进行组合出复杂表达式。
5、循环
(1)while语法:while command
do list
done
例:输出1~10。
#!/bin/sh
x=1
while [ $x –le 10 ]
do
echo $x
x=$(($x+1))
done
还可以进行嵌套。
(2)until语法:until command
do list
done
(3)for语法:for name in word1 word2…wordN
do list
done
例:输出1~10。
#!/bin/sh
x=1
for x in 1 2 3 4 5 6 7 8 9 10
do
echo $x
done
(4)select语法:select name in word1 word2…wordN
do list
done
(5)break和continue。
6、参数(有些地方不明白)
处理参数和选项采用如下方法:使用case语句手工处理参数和选项,使用getopts处理选项。
(1)特殊变量
7、输入输出
1)向终端输出:echo、printf(格式化输出,位于/usr/bin中)
2)输出重定向:
“>”(把输出的内容重定向到指定的文件中)
“>>”(把输出的内容追加到指定的文件尾部)
tee(同时重定向到屏幕和文件) :command | tee file
3)输入重定向
Command < file,例:Mail [email protected] < File_Exam
Command << delimiter
Document
Delimiter
4)读取用户输入
read name 直到用户输入回车为止。
5)管道
6)重定向到同一个文件
例:ll >file1 >&file2
8、函数
1)创建和使用
name( ) { list; } 例如:ls1( ) { ls –l; }
cd( ) { chdir ${1:-$HOME }; PSI=” ’pwd’ $” ; export PSI; }
激活:$name
2)函数间协同工作并共享数据
略,P138
9、文本过滤器
1)最常用的有:head, tail, grep, sort, uniq, tr。
2)head格式:head [ -n lines ] files ,其中[ -n lines ]不写默认查看前10行,带的话指定前n行。
组合使用,例检索5个最常访问的文件:ls –l ut /home/public_html | head -5
3)tail格式:tail [ -n lines ] files ,其中[ -n lines ]不写默认查看后10行,带的话指定后n行。
4)grep格式:grep word file ,例:grep creat test2.sql test.sql
grep -i word file ,不考虑大小写。
grep -v word file/dir ,不包括该单词的。
grep -n word file ,一起写出行号。
grep -l word dir ,只列出包含它的文件名。
5)tr:将一个集合中的所有字符改变成别一个集合中的字符,也可用于删除字符集。
tr ‘set1’ ‘set2’
6)sort:为输入文件占的行进行分类。
例统计一个单词使用了多少次。
7)uniq:打印出文件中所有的唯一行。若某行多次,只打一个。
uniq filename
10、使用正规表达式过滤文本
1)command ‘script’ filenames
command是awk或sed,script是可以被awk或sed理解的命令清单,filenames表示命令所作用的文件清单。
2)正规表达式基本构造块包括:
普通字符:大小写字母、数字、字符。
元字符:.、*、[chars]、^、$、/。例:/a.c/匹配如a+c, a-c, abc行。
3)使用sed
/p打印,/d删除,/s/pattern1/pattern2将2代替1。
例:$sed ‘/0/.[0-9][0-9]$/p’ fruit_prices.txt ,告诉sed打印所有匹配模式/0/.[0-9][0-9]$的行。
11、使用awk过滤文本
编程语言。(见详解)
12、各种工具
1)eval命令:第二次处理命令行时使用。
2):命令:返回一个完成代码0,用于指示命令成功完成。
3)type命令:告诉用户一个指定命令的全路径。
4)sleep命令:暂停给定秒数,sleep n
5)find命令:检索,find start-dir options actions,例find / -nme alpha –print
6)xargs命令:从标准输入接收单词并将其提供给给定命令作为参数,cat filelist | xargs rm。
7)expr命令:执行简单整数算术运算,$expr 8/3
8)bc命令:不局限于整数的算术工具。
9)remsh/rsh/rcmd/remote命令:远程Shell
SHELL编程三高级主题
1、信号处理
1)信号位于C语言头文件signal.h中。
2、调试
3、使用函数解决问题
1)创建库
创建Shell函数库就像创建Shell脚本,主要区别是库只包含函数,而脚本包含函数和主代码。
2)使用库中包含的函数:.file
3)常见函数:printERROR, printWARNING, pringUSAGE, promptRESPONSE, getSpaceFree, getSpaceUsed, getPID, getUID, toUpper, toLower, isSpaceAvailable, isUserRoot。
4、使用Shell脚本解决问题
5、脚本可移植性
1)判断unix版本:uname
操作系统发行版本号:uname –rs
硬件类型:uname –m
主机名:uname –n
2)提高可移植性技巧:条件执行和抽取。
6、Shell编程疑难解答
shell编程实例:
1、expr计算整数变量值
格式 :expr arg
例子:计算(2+3)×4的值
1、分步计算,即先计算2+3,再对其和乘4
s=expr 2 + 3
expr $s * 4
2、一步完成计算:
expr expr 2 + 3
* 4
–说明:
运算符号和参数之间要有空格分开;
通配符号(),在作为乘法运算符时要用\、“”、‘’符号修饰
–:expr 3 * 2 expr 3 “” 2 expr 3 ‘*’ 2
`(反引号)与键盘上的~同一个键上的符号
[fsy@localhost ~]$ s=expr 2 + 3
[fsy@localhost ~]$ echo $s
5
[fsy@localhost ~]$ expr $s * 4
20
[fsy@localhost ~]$ expr expr 2 + 3
* 4
20
[fsy@localhost ~]$ expr 2 * 3
6
[fsy@localhost ~]$ expr 2 "" 3
6
[fsy@localhost ~]$ expr 2 '' 3
6
[fsy@localhost ~]$ expr 2 * 3
expr: 语法错误
[fsy@localhost ~]$
2、let命令
格式:let arg1 [arg2 ......]
说明:
与expr命令相比,let命令更简洁直观
[ ]表示可以有多个参数,arg n (n=1,2…)
运算符与操作数据之间不必用空格分开,但表达式与表达式之间必须要用空格分开
当运算符中有<、>、&、|等符号时,同样需要用引号(单引号、双引号)或者斜杠来修饰运算符
–例子:计算(2+3)×4的值
[fsy@localhost ~]$ let s=(2+3)*4
[fsy@localhost ~]$ echo $s
20
[fsy@localhost ~]$
3、for语句——坑爹的开始...... 和其他语言的for不同!
对一组参数进行一个操作
语法格式:
for 变量 in 列表
do
命令行(通常用到循环变量)
done
说明:
–“列表”为存储了一系列值的列表,随着循环的进行,变量从列表中的第一个值依次取到最后一个值;
–do和done之间的命令通常为根据变量进行处理的一系列命令,这些命令每次循环都执行一次;
–如果“ in 列表”部分省略掉,Bash则认为是“in $@”,即执行该程序时通过命令行传给程序的所有参数的列表。
例1、自定义列表
#!/bin/bash
for var in one two three four five
do
echo ------
echo '$var is' $var
done
运行输出:
$var is five
例2、以命令返回值作为列表
#!/bin/bash
for var in ls
do
echo -----
echo $var
done
运行输出:
例3、命令行参数指定为列表中的数值
#!/bin/bash
for var
do
echo "It's $var"
done
运行输出:
[fsy@localhost ~]$ sh c.sh a b c d
It's a
It's b
It's c
It's d
4、while语句
语法格式:
while 表达式
do
命令行
done
说明:
–while循环中,只要条件为真,就执行do和done之间的循环命令;
–避免生成死循环。
例如:
#!/bin/bash
num=1
while [ $num -le 10 ]
do
echo -e "\t the num is $num"
let num=num+1
done
运行输出:
the num is 1
the num is 2
the num is 3
the num is 4
the num is 5
the num is 6
the num is 7
the num is 8
the num is 9
the num is 10
5、until语句
语法格式:
unitil 表达式
do
命令行
done
说明:
–until循环中,只要条件不为真,就执行do和done之间的循环命令,或者说,在until循环中,一直执行do和done之间的循环命令,直到条件为真;
–避免生成死循环。
例:计算1到10的和
#!/bin/bash
sum=0
num=10
until test $num -eq 0
do
sum=expr $sum + $num
num=expr $num - 1
done
echo "sum = $sum"
运行输出
sum = 55
6、shift语句
shift语句:将变量的值依次向左传递,并形成一组新的参数值
–例:位置变量当前值为:1=file1 2= file2 3=file3
– 执行一次shift后为:1=file2 2=file3
还可以在shift命令中指定位置变量转移的次数
–shift n
例:
#!/bin/bash
while [ -n "$*" ]
do
echo $1 $2 $3 $4 $5 $6
shift
done
运行输出
[fsy@localhost scripts]$ sh b.sh 1 2 3 4 5 6 7
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7
4 5 6 7
5 6 7
6 7
7
7、if语句
if 语句的一般形式 :
if 条件表达式
then #当条件为真时执行以下语句
命令列表
else #当条件为假时执行以下语句
命令列表
fi
if的测试部分利用test命令实现,也可以利用一般命令执行成功与否来判断。如果命令正常结束,返回值为0,条件测试为真; 否则返回值不为0,条件测试为假
例:
#!/bin/bash
if test -f "$1"
then
echo "$1 is an ordinary file"
else
echo "$1 is not an ordinary file"
fi
运行输出:
[fsy@localhost scripts]$ sh c.sh abb
abb is not an ordinary file
[fsy@localhost scripts]$ sh c.sh a.sh
a.sh is an ordinary file
[fsy@localhost scripts]$
8、case语句
取值后面必须为单词in,每一个模式必须以右括号结束。取值可以为变量或常数。取值检测匹配的每一个模式,一旦模式匹配,其间所有命令开始执行直至;;。执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用*号捕获该值,再接受其他输入。
[注]
1.模式字符串中可以使用通配符
2.如果一个模式字符串中包含多个模式,那么各模式之间应以竖线(|)隔开,表各模式是“或”的关系,即只要给定字符串与其中一个模式相配,就会执行其后的命令列表。
3.各模式字符串应是唯一的,不应重复出现,并且要合理安排它们的出现顺序,例如,不应将“”作为头一个模式字符串,因为“”可以与任何字符串匹配,若第一个出现,就不会再检查其他模式了。
4.case语句以关键字case开头,以关键字esac结束。
5.case的退出(返回)值是整个结构中最后执行的命令的退出值。若没有执行任何命令,则退出值为0.
例:
#!/bin/bash
case $1 in
1)
echo " you choice is 1";;
2)
echo " your choice is 2";;
*)
echo " your choice is others";;
esac
运行输出:
[fsy@localhost scripts]$ sh d.sh 1
you choice is 1
[fsy@localhost scripts]$ sh d.sh 2
your choice is 2
[fsy@localhost scripts]$ sh d.sh 3
your choice is others
9、break与continue
–1、break:用于立即终止当前循环的执行,break命令可以使用户从循环体中退出来。
–语法:break[n] ,其中,n表示要跳出几层循环,默认值为1
–2、continue:跳过循环体中在其之后的语句,会返回到本循环层的开头,进行下一次循环。
–语法:continue[n],其中,n表示从包含continue语句的最内层循环体向外跳到第几层循环,默认值为1,循环层数是由内向外编号。
10、函数
函数:由函数标题和函数体两部分组成。标题是函数名。函数体是函数内在的命令集合。标题名称必须唯一。变量均为全局变量,没有局部变量。
格式:
[function] 函数名() 或 [function]函数名() {
{ 命令1
命令1 …
… }
}
例:
#!/bin/bash
num=1
hello()
{
echo "hello boy~ It's our $num meeting"
let num=num+1
}
hello
hello
hello
运行输出
hello boy~ It's our 1 meeting
hello boy~ It's our 2 meeting
hello boy~ It's our 3 meeting
11、select语句
格式:
select 变量 in 列表
do
命令行(通常用到循环变量)
done
制作一个选择表,在列表中选择一个选项执行命令行。如果选择的变量不在列表序列中,则返回一个空值。需要用break退出循环。
例子:
#!/bin/bash
echo "a is 5 ,b is 3. Please select your method: "
a=5
b=3
select var in "a+b" "a-b" "a*b" "a/b"
do
break
done
case $var in
"a+b")
echo 'a+b= 'expr $a + $b
;;
"a-b")
echo 'a-b= 'expr $a - $b
;;
"ab")
echo 'ab= 'expr $a \* $b
;;
"a/b")
echo 'a/b= 'expr $a / $b
;;
*)
echo "input error"
esac
运行输出:
[fsy@localhost scripts]$ sh e.sh
a is 5 ,b is 3. Please select your method:
1) a+b
2) a-b
3) a*b
4) a/b
#? 1
a+b= 8
本篇博客出自 阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/6724228
这里说的“瑞士×××”是指那些简单的一句命令就能完成其它高级语言一大片代码才能完成的工作。
下面的这些内容是Quora网站上Joshua Levy网友的总结:
通过sort/uniq获取文件内容的交集、合集和不同之处:假设有a、b两个文本文件,文件本身已经去除了重复内容。下面是效率最高的方法,可以处理任何体积的文件,甚至几个G的文件。(Sort对内存没有要求,但也许你需要用 -T 参数。)可以试着比较一下,你可以看看如果用Java来处理磁盘上文件的合并,需要用多少行代码。
cat a b | sort | uniq > c # c 是a和b的合集
cat a b | sort | uniq -d > c # c 是a和b的交集
cat a b b | sort | uniq -u > c # c 是a和b的不同
汇总一个文本内容里第三列数字的和(这个方法要比用Python来做快3倍并只需1/3的代码量):
awk ‘{ x += $3 } END { print x }’ myfile
如果你想查看一个目录树里的文件的体积和修改日期,用下面的方法,相当于你挨个目录做”ls -l”,而且输出的形式比你用”ls -lR”更可读:
find . -type f -ls
使用xargs命令。这个命令非常的强大。注意每行上你可以控制多少个东西的执行。如果你不确定它是正确的执行,先使用xargs echo。同样,-I{} 也非常有用。例子:
find . -name *.py | xargs grep some_function
cat hosts | xargs -I{} ssh root@{} hostname
假设你有一个文本文件,比如一个web服务器日志,在某些行上有一些值,比如URL中的acct_id参数。如果你想统计每个acct_id的所有请求记录:
cat access.log | egrep -o ‘acct_id=[0-9]+’ | cut -d= -f2 | sort | uniq -c | sort -rn
转载于:https://blog.51cto.com/weimouren/2162542