Linux Shell Script的基础知识

来源:互联网 发布:易吧进销存软件下载 编辑:程序博客网 时间:2024/05/22 03:49

Shell Script 就像是早期DOS年代的批处理文件(.bat), 执行一个档案可以一次执行多个命令

Shell Script 提供数组,循环,条件,逻辑判断等重要的功能,可以直接以Shell来撰写程序

而不必使用类似C程序语言等传统程序撰写的语法,由于是利用Shell与相关工具指令,所以不需要编译

即可执行,且拥有不错的除错(debug)工具

Shell Script可以帮助:

1 自动化管理的重要依据,写个简单的script程序可以帮你每日自动处理分析登录档,追踪流量,监控用户使用主机状态

以上等等的操作,就需要一个良好的Shell script来帮忙的

2 追踪与管理系统的重要工作,Linux系统的服务启动的接口是在 /etc/init.d这个目录下,目录下的所有档案都是

scripts,另外包括开机过程都是利用shell script来帮忙搜索系统的相关设定数据,然后再代入各个服务的设定参数

3 数据入侵检测功能 , 系统中大多将异状记录在系统记录器,也就是我们常常提到的【系统注册表档】,固定的时间

去分析系统注册表档,若有问题,则立刻通知管理员,或者立刻加强防火墙的设定规则。或者判断该封包尝试几次还是

联机失败之后,就予以抵挡住该IP之类的举动,我们可以将以上的操作写入一个shell script去分析.

4  连续指令单一化,script最简单的功能就是帮我们把一大串的指令汇整在一个档案里面,而直接执行该档案就可以

执行那一串指令段了

5 简易的数据处理,shell script功能强大,可以对数据的比对,文字数据的处理,撰写方便,速度又快

6 跨平台支持不学习历程较短 shell script的语法是相当有亲和力的,而不是机器码,较容易学习

不过 虽然shell script号称是程序,但实际上,shell script处理数据的速度不太快的,shell script用的是外部的指令

与bash shell的一些默认工具,常常会去呼叫外部函数库,所以不适宜处理大量数值运算上,因为shell scripts的

速度较慢,且使用的CPU的资源较多,造成主机资源的分配不良,不过我们通常利用shell script来处理服务器的侦测

不会有大量的运算的需求,所以没事.

Shell Script 的撰写中需要用到底下的注意事项

1 读取到一个Enter符号(CR) , 就尝试开始执行该行(或该串)命令

2 如果一行内容太多,可以使用【\[enter]】来延伸至下一行

3 #号可做为批注,任何在#号后面的资料将全部被视为批注文字而被忽略

直接指令下达:

shell.sh 档案必须具备可读可执行的权限

绝对路径:使用 /home/dmtsai/shell.sh

相对路径:./shell.sh

变量【path】功能 : 将shell.sh 放在PATH指定的目录内,例如:~/bin/

以 bash 程序来执行:透过『 bash shell.sh 』戒『 sh shell.sh 』来执行

可以使用sh的参数 -n或-x来检查与追踪shell.sh 的语法是否正确

shell script的内容大致分为

1.第一行 #!/bin/bash在宣告这个scripts使用的shell名称

当文件被执行时,会加载bash的相关环境配置文件

(一般来说就是non-login shell 的~/.bashrc),并且执行bash来使我们底下的指令能够执行,如果没有这行

可能造成程序无法判断使用什么样的shell来执行

2.第二行 程序内容的说明:

整个script当中,除了第一行的【#!】是用来宣告shell的之外,第二行以下用来说明整个程序的基本数据

1 内容和功能 2版本信息 3作者和联络方式 4 建档日期 5 历史记录

3.主要环境变量的宣告:

建议务必要将一些重要的环境变量设定好,PATH与LANG(如果有使用到输出相关的信息)是当中最重要的

可以直接下达一些外部指令,而不必写绝对路径比较好

4 主要程序部分

就将主要的程序写好即可

5 执行成果告知

可以使用$?这个变量来观察,也可以使用exit这个命令让程序中断,并且回传一个值给系统,例如exit 0

代表回传了一个0给系统,所以当执行完这个script后,若接着下达echo $? 则可得到0这个值,exit n(n是个数字)

我们可以根据这个n来自定义错误讯息,让这支程序变得更加smart

当内容执行程序中包含printf或者用echo -e接着那些特殊的按键也可以听到『咚』的一声

编写Shell Script需要记录

script的版本信息

script的作者和联系方式

script的版权宣告方式

script的History历史记录

script内较特殊的指令,需要使用绝对路径的方式来下达

script运作时需要的环境变量预先宣告和设定

最好使用【tab】按键的空格向后推,最好使用vim,可以在编辑的时候发现错误

编写对谈式脚本:变量内容由用户决定

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 声明PATH这个环境变量

export PATH // 声明为环境变量

read -p "Please input your first name: " firstname # 提示使用者输入 

read -p "Please input your last name: " lastname # 提示使用者输入 

echo -e "\nYour full name is: $firstname $lastname" # 结果由屏幕输出

根据日期变化,利用date进行档案的建立

创建 filename_20090212, filename_20090213, filename_20090214

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 

export PATH

# 1. 讥使用者输入文件名,幵叏得 fileuser 这个发量;

read -p "Please input your filename: " fileuser

2. 为了避免使用者随意按 Enter ,利用变量功能分析档名是否有设定? filename=${fileuser:-"filename"} # 开始判断有否配置文件名

# 3. 开始利用 date 指令来叏得所需要的档名了;

date1=$(date --date='2 days ago' +%Y%m%d) # 前两天的日期 

date2=$(date --date='1 days ago' +%Y%m%d) # 前一天的日期 

date3=$(date +%Y%m%d) # 今天的日期 

file1=${filename}${date1} # 底下三行在配置文件名

file2=${filename}${date2} 

file3=${filename}${date3}

# 4. 将档名建立吧! 

touch "$file1" # 底下三行在建立档案 

touch "$file2" 

touch "$file3"

简单的加减乘除

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 

export PATH echo -e "You SHOULD input 2 numbers, I will cross them! \n" 

read -p "first number: " firstnu 

read -p "second number: " secnu 

total=$(($firstnu*$secnu)) 

echo -e "\nThe result of $firstnu x $secnu is ==> $total"

declare -i total=$firstnu*$secnu 』 也可以使用这个方式来运行!

var=$((运算内容))

脚本除了使用之前的几种方式执行,还可以使用souce和小数点 (.)来执行

无论使用哪种方式运行,该script都会使用一个新的bash环境来执行脚本内的指令,

其实script是在子程序的bash内执行的,不使用export的话,当子程序完成后,在子程序中的各项变量

或动作将会结束而不会回传到父程序中。

而加上export的话,执行echo $firstname $lastname 这两个变量在父程序的bash中还是存在的

利用 source 来执行脚本:在父程序中执行

因为source对script的执行方式会在父程序中执行的,因此各项动作都会在原本的bash内生效

,这也是为啥不注销系统而要让某些写入~/.bashrc的设定生效时,需要使用source ~/.bashrc 而不能使用 bash ~/.bashrc

善用表达式

长长通过$?的返回值来判断后续的指令是否进行执行,但是有更简单的可以进行条件判断,那就是【test】这个指令

检查 /dmtsai 是否存在时,test -e /dmtsai

test -e /dmtsai && echo "exist" || echo "Not exist" 表示存在显示前者,不存在显示后者

test的常用参数

关亍某个档名的『文件类型』刞断,如 test -e filename 表示存在否

1. 关亍某个档名的『文件类型』刞断,如 test -e filename 表示存在否 

-e 该『档名』是否存在?(常用) 

-f 该『档名』是否存在且为档案(file)?(常用) 

-d 该『文件名』是否存在且为目录(directory)?(常用) 

-b 该『档名』是否存在且为一个 block device 装置? -

c 该『档名』是否存在且为一个 character device 装置? 

-S 该『档名』是否存在且为一个 Socket 档案?

 -p 该『档名』是否存在且为一个 FIFO (pipe) 档案?

 -L 该『档名』是否存在且为一个连结档?

2. 关亍档案的权限侦测,如 test -r filename 表示可读否 (但 root 权限常有例外) 

-r 侦测该档名是否存在且具有『可读』的权限?

 -w 侦测该档名是否存在且具有『可写』的权限?

 -x 侦测该档名是否存在且具有『可执行』的权限? 

-u 侦测该文件名是否存在且具有『SUID』的属性?

 -g 侦测该文件名是否存在且具有『SGID』的属性? 

-k 侦测该文件名是否存在且具有『Sticky bit』的属性? 

-s 侦测该档名是否存在且为『非穸白档案』?

3. 两个档案之间的比较,如: test file1 -nt file2 

曼联转会-nt (newer than)判断 file1 是否比 file2 新

 -ot (older than)判断 file1 是否比 file2 旧

 -ef 判断 file1 不 file2 是否为同一档案,可用在判断 hard link 的刞定上。 主要意义在判定,两个档案是否均指向同一个 inode 哩!

 4. 关亍两个整数之间的判定,例如 test n1 -eq n2 

-eq 两数值相等 (equal) 

-ne 两数值丌等 (not equal) 

-gt n1 大亍 n2 (greater than) 

-lt n1 小亍 n2 (less than) 

-ge n1 大亍等亍 n2 (greater than or equal) 

-le n1 小亍等亍 n2 (less than or equal)

5. 判定字符串的数据 

test -z string 判定字符串是否为 0 ?若 string 为空字符串,则为 true 

test -n string 判定字符串是否非为 0 ?若 string 为空字符串,则为 false。 注: -n 亦可省略 

test str1 = str2 判定 str1 是否等亍 str2 ,若相等,则回传 true 

test str1 != str2 判定 str1 是否不等亍 str2 ,若相等,则回传 false 

6. 多重条件刞定,例如: test -r filename -a -x filename 

-a (and)两状况同时成立!例如 test -r file -a -x file,则 file 同时具有 r 不 x 权限时,才回传 true。 

-o (or)两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r 戒 x 权限时,就可回传 true。 

! 反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true

再来写一个脚本,条件:

1. 这个档案是否存在,若不存在则给予一个『Filename does not exist』的讯息,并中断程序;
2. 若这个档案存在,则判断他是个档案戒目录,结果输出『Filename is regular file』戒
『Filename is directory』
3. 刞断一下,执行者的身份对这个档案戒目录所拥有的权限,并输出权限数据!

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH 

# 1. 讥使用者输入档名,幵且刞断使用者是否真的有输入字符串? 

echo -e "Please input a filename, I will check the filename's type and \ permission. \n\n" 

read -p "Input a filename : " filename 

test -z $filename && echo "You MUST input a filename." && exit 0 # 

2. 刞断档案是否存在?若丌存在则显示讯息幵结束脚本 

test ! -e $filename && echo "The filename '$filename' DO NOT exist" && 

exit 0 

# 3. 开始刞断文件类型不属性

 test -f $filename && filetype="regulare file"

 test -d $filename && filetype="directory"

 test -r $filename && perm="readable" 

 test -w $filename && perm="$perm writable"

 test -x $filename && perm="$perm executable" 

# 4. 开始输出信息! 

echo "The filename: $filename is a $filetype" 

echo "And the permissions are : $perm"

利用判断符号 [ ]

以上这个符号用来进行数据的判断的,如果我想要知道$HOME这个变量是否为空的,可以这样做

[ -z "$HOME" ] ; echo $? 中括号的两端还有等号的两边需要有空格符来分隔

还要注意一个等号代表变量的设定,而两个等号代表逻辑的判断

在中括号内的变量,最好都以双引号括号起来;

在中括号内的常数,最好都以单或双引号括号起来

Shell Script的默认变数

例如 : /etc/init.d/syslog restart

如果指令后面接参数,那么一个指令就能够处理完毕而不需要手动再次输入一些变量行为

script 针对参数已经设定好一些变量名称了

例如:/path/to/scriptname opt1 opt2 opt3 opt4

                 $0                            $1     $2     $3     $4

执行脚本的档名是$0这个变量 第一个接的参数是$1 

$# 代表后接的参数【个数】,以上表为例这里显示为4

$@ 代表【"$1" "$2" "$3" "$4"】之意,这个变量是独立的(用双引号括起来)

$* 代表 【"$1 $2 $3 $4"】

shift 命令的作用是造成参数变量号码偏移

sh sh08.sh one two three four five six <==给予六个参数

shift 1 则是把第一个变量给去掉了

shift 3 则是把第二到第四的变量给去掉了

最后只剩下变量 5和 6了

条件判断式

if ......elif.......else,

case $变量 in

function功能,为了处理共通的模块,方法中的$1和shell script中的$1 是不同的,前者是调用方法时传的参数

而后者是调用脚本时传递的参数

loop 不定循环

while do done , until do done  不定循环

while [ condition ] <==中括号内的状态就是判断式
do
<==do 是循环的开始!
程序段落
done
<==done 是循环的结束
当condition条件成立时,就进行循环,直到condition的条件不成立才停止

还有一种不定循环的方式
until [ condition ]
do
程序段落
done

这种判断表示,当condition条件成立时,就终止循环,否则就持续进行循环的程序段

for...do...done 固定循环

for animal in dog cat elephant
do
echo "There are ${animal}s.... "
done

for...do...done 的另一种写法
for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done

shell script的追踪与debug

选项与参数:

-n :不要执行 script,仅查询语法的问题;

-v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;

-x :将使用到的 script 内容显示到屏幕上,这是很有用的参数!


原创粉丝点击