shell脚本编写的整理(1)

1、shell脚本的特点及用途
2、全局变量、局部变量、本地变量
3、位置变量、特殊变量、只读变量
4、退出状态、算数运算、赋值
5、逻辑运算、条件测试、数值测试
6、文件测试、文件权限测试、文件属性测试
7、read命令、bash的配置

1、shell脚本的特点及用途

程序:指令+数据

程序编程风格:

过程式:以指令为中心,数据服务于指令

对象式:以数据为中心,指令服务于数据

shell程序:提供了编程能力,解释执行

编程逻辑处理方式:顺序执行   循环执行   选择执行

shell编程:过程式、解释执行

格式要求:首行shebang机制    #!/bin/bash

shell脚本用途: 自动化常用命令 ;执行系统管理和故障排除;创建简单的应用程序;处理文本或文件

检查语法错误:bash -n f1.sh

调试执行过程:bash -x f1.sh

变量

按数据的存储方式分为:字符和数字(整型,浮点型)

bash不支持浮点

强类型:变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转换。一般定义变量时必须指

定类型、参与运算必须符合类型要求;调用未声明变量会产生错误

弱类型:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐

式类型转换;变量无须事先定义可直接调用

bash属于弱类型

name=”mage”

echo $name

mage

如果更改name=”wang”

echo $name

wang

在内存空间里面有另一块位置被wang占用,原来mage那一个占用并没有消失!只是没有了引用

保留原文件的格式必须加双引号

如name=`cat /etc/fstab`

echo “$name”则有格式

echo  $name 没有格式

不要使用shell的保留关键字如if,for 、,hostname

变量名尽量用英文单词,不要用英文的简写,容易混淆,或者

student_name

统一命名方式:驼峰法

第一个单词首字母不大写,后续的所有单词的首字母全大写

studentNameFile

 

bash 中变量的种类

运行脚本就是在当前shell开启一个子进程

显示当前进程编号

echo $$

查看进程树命令

pstree -p

新增bash

bash

退出当前bash

exit

2、全局变量、局部变量、本地变量

环境变量

就是全局变量,生效范围为当前shell进程及其子进程

查询系统中当前所有环境变量

env

export

declare -x

例子:

1.

export name=mage

则name变为全局变量

在当前以及子进程里执行echo $name都是mage

注意:全局变量只能父进程传子进程,不能子进程传父进程

2.删除变量命令

unset name

注意:这里的变量name不用加$,一般能识别出就不加,但是有些不能识别出的要加,这个要经验积累.

一般编写完脚本最后都会用unset命令清楚变量这个是好习惯!!

set     查看系统所有变量,包括本地变量,环境变量

局部变量: 生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效

本地变量:生效范围为当前shell进程中某代码片段,通常指函数

3、位置变量、特殊变量、只读变量

位置变量

用于让脚本在脚本代码中调用通过命令行传递给它的参数

$1 $2 ….:对应调用第1,第2个等参数,shift[n]换位置

例子:

$1,$2表示脚本后的第1和第2个参数

例如:    backup.sh a b c

$1就是a  $2就是b

shift   变量移动

shift  移动一次

shift 2  移动两次

set — 清空所有位置变量

特殊变量

$0 : 表示命令本身

$#:传递给脚本参数的个数

$*:传递给脚本的所有参数,全部参数合为一个字符串

$@:引用传递给脚本的所有参数,每个参数为独立字符串

($@和$*只有被双引号包起来的时候才会有差异)

$_:前一个命令最后一个字符串

例子:

1.echo a b c    结果a b c

echo $_      结果c

2. 在/root/bin下写脚本arg.sh

echo “1st arg is $1”

echo “2st arg is $2”

echo “3st arg is $3”

echo “All args are $*”

echo “All args are $@”

echo “The args number is $#”

echo “The script name is $0”    如果不要路径名则 `basename $0`

然后执行

arg.sh xxx yy zzzz

显示

1st arg is xxx

2st arg is yy

3st arg is zzzz

All args are xxx yy zzzz

All args are xxx yy zzzz

The args number is 3

The script name is /root/bin/arg.sh

注意: 如果有第10个参数,则脚本里应写为:

echo “10st arg is ${10}” 否则系统会把$10误认为 $1和0上题就是显示a0

3.scp f1 wang@172.20.102.77:/home/wang/bin

写脚本scp.sh

echo “Start copy..”

scp $* wang@172.20,102.77:/home/wang/bin

echo “copy is finished”

执行scp.sh f1

就是把f1文件传送到172.20.102.77里的用户wang登陆的,/home/wang/bin目录下

第一次连会问你输入yes,以后不用,但是要密码

附带快速改密码方法,例如想把wang密码改成magedu则

echo magedu | passwd –stdin wang

只读变量

只能声明,但不能修改和删除

readnoly name=mage

declare -r name

查看只读变量:

readonly -p

( )只影响括号里的信息,原理是开启一个子进程,不影响父进程,而且执行完后子进程自动关闭

换句话说就是(      )里面的任务是一次性的,而不会影响环境

例如:

1.(umask 666;touch /data/f1)

执行完后系统umask还是0022,f1的权限却为000

2.想执行一些任务,结束后自动回到当前目录

(cd /data/ ;rm -rf /data/*)

而{ ; ;  }会影响当前shell的环境

而且格式必须为{ ; ; },括号里两边带有空格

例子:

{   name=mage;echo $name;  }

echo $name

总结:小括号开启子shell不影响当前环境,大括号不开启子shell影响当前环境

一题弄清楚( )的特性

x=1;echo “pid=$$”;(echo “subpid=$$”;echo “subx=$x”;x=2;echo “subx2=$x”);echo x=$x

结果

pid=2887

subpid=2887

subx=1

subx2=2

x=1

说明当前变量可以传递到()里面,而()里面的变量不会传递到外面,而且()里的子进程号和当前进程号相同。

注意:为脚本创建软连接脚本,然后执行软连接脚本,会发现$0参数为软连接而非原来的脚本,利用这个特性,可

以为同一脚本设置多个软连接脚本,各软连接脚本实现不同功能.

4、退出状态、算数运算、赋值

退出状态

进程使用退出状态来报告成功或者失败

0代表成功,1-255代表失败

$? 变量保存最近的命令退出状态

exit [n]:自定义退出状态码

注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命

令后面的数字

注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行

的最后一条命令的状态码

例如:

静默模式

grep -q root /etc/passwd

echo $?

0

就是找到了root

返回信息为0就是成功,其他数字就是失败.

如果想定制返回结果则用 exit num

例如:

ls

exit 10

则echo $?就是10

算数运算

bash中的算术运算:help let

+, -, *, /, %取模(取余), **(乘方)

实现算术运算:

(1) let var=算术表达式

(2) var=$[算术表达式]

(3) var=$((算术表达式))

(4) var=$(expr arg1 arg2 arg3 …)

(5) declare –i var = 数值

(6) echo ‘ 算术表达式’ | bc

乘法符号有些场景中需要转义,如*

bash有内建的随机数生成器:$RANDOM(0-32767)

echo $[$RANDOM%50] :0-49之间随机数

let 用法

1.

x=10

y=20

let z=x+y

echo $z

30

2.

let x++

x=x+1

echo $x

11

3.

m=2

n=3

sum=$[m+n]

echo $sum

5

4.

对100取模就是取余数

let result=100%3

echo $result

1

或者写成

result=$[100%3]

echo $result

5.字体随机颜色

COLOR=$[RANDOM%7+31]; echo -e “\e[1;${COLOR}mcolor\e[0m”

6.expr用于计算

expr 1 + 2

3

记得有空格

expr 3 \* 2

expr 3 / 2

1

是因为不支持浮点

赋值

增强型赋值:

+=, -=, *=, /=, %=

let varOPERvalue

例如:let count+=3

自加3后自赋值

自增,自减:

let var+=1

let var++

let var-=1

let var–

x+=2 等价于 x=x+2

5、逻辑运算、条件测试、数值测试

逻辑运算

非: !

! 1=0

! 0=1

0 false

1 true

& 并且 and

0&0=0

0&1=0

1&0=0

1&1=1

| 或者  or

0|0=0

0|1=1

1|0=1

1|1=1

短路与 &&

短路或||

0&&0=0

0&&1=0

1&&0=0

1&&1=1

0||0=0

0||1=1

1||0=1

1||1=1

cmd1 && cmd2

如果cmd1为假,cmd2不需要执行,反之cmd1为真,需要cmd2执行

cmd1||cmd2

如果cmd1为真,cmd2不需要执行,反之cmd1为假,需要cmd2执行

XOR 异或

这里是二进制

0^1=1

0^0=0

1^0=1

1^1=0

例子:

a=2

b=3

let c=a^b

echo $c

1

2的二进制是10

3的二进制是11

10

11

01的二进制就是1

所以结果 $c为1

条件测试

判断某需求是否满足,需要由测试机制来实现

专用的测试表达式需要由测试命令辅助完成测试过程

评估布尔声明,以便用在条件性执行中

$?

若真,则返回0

若假,则返回1

测试命令

test 命令

例子:

str1=aaa

str2=bbb

test $str1 = $str2

echo $?

1

str2=aaa

test $str1 = $str2

echo $?

0

[ $str1 = $str2 ]

echo $?

0

[ -z $var ]

echo $?

0

(因为 $var 没有赋值)

var=haha

[ -z $var ]

echo $?

1

[ “abc” ]

echo $?

0

因为”abc”不是变量,属于”有东西”

[ -n “abc” ]

为非空为真

字符型:

x=haha;y=xixi; [ “$x” = “$y” ] && echo equal || echo no equal

数字型:

m=10

n=20

[ $m -eq $n ] && echo equal || echo no equal

数值测试

-v 测试变量var1是否已经被设置

例:

[ -v var1 ] && echo set

var1=123

运行则显示 set

注意: “”一样代表有值!

-v VAR

变量VAR是否设置

数值测试:

-gt 是否大于

-ge 是否大于等于

-eq 是否等于

-ne 是否不等于

-lt 是否小于

-le 是否小于等于

字符串测试:

== 是否等于

> ascii码是否大于ascii码

< 是否小于

!= 是否不等于

=~ 左侧字符串是否能够被右侧的PATTERN所匹配

注意: 此表达式一般用于[[ ]]中;扩展的正则表达式

-z “STRING“ 字符串是否为空,空为真,不空为假

-n “STRING“ 字符串是否不空,不空为真,空为假

注意:用于字符串比较时的用到的操作数都应该使用引号,就是在中括号里面都应该加引号

[ “$var” = “” ] 等价 [ -z “$var ]

例子

判断wang用户对文件是否有读和写的权限同时有则打印读和写

[ -r /etc/issue -a -w /etc/passwd] && echo “read and write”

没显示,如果改成-o则有显示

-a 是并且的关系

-o 是或者关系

设置一个脚本如果磁盘利用率高于等于80%则报警

USE_RATIO=`df | grep “sd[a-z]” | tr -s ‘ ‘ ‘%’ |cut -d% -f5 |sort -nr | head -1`

[ $USE_RATIO -ge 80 ] && `wall “disk will be full” `

=~ 要用[[]],而且是扩展正则表达式

例子:

1.n=12

[[ “$n” =~ ^[0-9]+$ ]] && echo digit || echo no digit

digit

2.! 1=0

!  0=1

[ $# -ne 2 ]  && echo “Arg number is 2” && exit

[[  !  “$1” =~ ^[0-9]+$ ]]  && echo “$1 is not digit ” && exit

[[  !  “$2” =~ ^[0-9]+$ ]]  && echo “$1 is not digit ” && exit

uid1=`head -n$1 /etc/passwd | tail -n1 |cut -d: -f3`

uid2=`head -n$2 /etc/passwd | tail -n1 |cut -d: -f3`

echo sum=$[uid1+uid2]

3..sh后缀的文件则显示sh非则no sh

[[  $filename =~ .+\.sh$ ]] && echo sh || echo no sh

4.判断用户是否存在,存在则退出,不存在则创建用户并设置密码magedu

id $1 &> /dev/null

[ $? -eq 0 ] && echo user is exist && exit

useradd $1

echo magedu | passwd –stdin $1 &> /dev/null

echo “$1 is created”

6、文件测试、文件权限测试、文件属性测试

存在性测试

-a FILE:同-e

-e FILE: 文件存在性测试,存在为真,否则为假

存在性及类别测试

-b FILE:是否存在且为块设备文件

-c FILE:是否存在且为字符设备文件

-d FILE:是否存在且为目录文件

-f FILE:是否存在且为普通文件

-h FILE 或 -L FILE:存在且为符号链接文件

-p FILE:是否存在且为命名管道文件

-S FILE:是否存在且为套接字文件

文件权限测试:

-r FILE:是否存在且可读

-w FILE: 是否存在且可写

-x FILE: 是否存在且可执行

文件特殊权限测试:

-u FILE:是否存在且拥有suid权限

-g FILE:是否存在且拥有sgid权限

-k FILE:是否存在且拥有sticky权限

文件大小测试:

-s FILE: 是否存在且非空

文件是否打开:

-t fd: fd 文件描述符是否在某终端已经打开

-N FILE:文件自从上一次被读取之后是否被修改过

-O FILE:当前有效用户是否为文件属主

-G FILE:当前有效用户是否为文件属组

7、read命令、bash的配置

read 命令

使用read来把输入值分配给一个或多个shell变量

-p 指定要显示的提示

-s 静默输入,一般用于密码

-n N 指定输入的字符长度N

-d ‘字符’ 输入结束符

-t N TIMEOUT为N秒

read 从标准输入中读取值,给每个单词分配一个变量

所有剩余单词都被分配给最后一个变量

read -p “Enter a filename: “ FILE

例子:

1.read -p “Please input your name :” name

read -p “Please input your password :” passwd

echo “Your name is $name”

echo “Your password is $password”

2.头 35 脚 94 答案鸡23  兔 12

read -p ” head number : ” head

read -p ” feet number : ” feet

chook=$[(head*4-feet)/2]

rabbit=$[head -chook]

echo “chook number is $choook , rabbit number is $rabbit ”

完美版:

read -p “please input the head number :” head

read -p “please input the feet number :” feet

let chook=(4*head-feet)/2

let rabbit=head-chook

echo “the chook number is $chook ,the rabbit number is $rabbit”

bash如何展开命令行

1.把命令行分成单个命令词

2.展开别名

3.展开大括号的声明({})

4.展开波浪符声明(~)

5.命令替换$() 和 “)

6.再次把命令行分成命令词

7.展开文件通配(*、 ?、 [abc]等等)

8.准备I/0重导向(<、 >)

9.运行命令

shell登录两种方式

交互式登录:

(1)直接通过终端输入账号密码登录

(2)使用“ su – UserName” 切换的用户

执行顺序:/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile –>

~/.bashrc –> /etc/bashrc

非交互式登录:

(1)su UserName

(2)图形界面下打开的终端

(3)执行脚本

(4)任何其它的bash实例

执行顺序: ~/.bashrc –> /etc/bashrc –> /etc/profile.d/*.sh

批量赋值

支持重定向赋值

echo a b c > f1

read x y z < f1

echo $x  ; echo $y ; echo $z

a             b        c

会显示赋值成功

cat f1

aaa

bbb

ccc

cat f1 | read x y z

这样会赋值失败

read x y x <<< “i j k”

这样会赋值成功

判断yes和no

read -p “Do you agree ? yes or no:” ANS

[[ $ANS =~ ^([Yy]([Ee][Ss])?)$ ]] && echo “your answer is yes”

[[  $ANS  =~  ^([Nn][Oo]?)$  ]] && echo “your answer is no”

[[ !  $ANS =~ ^([Yy]([Ee][Ss])?)$  ]] && [[  ! $ANS  =~  ^([Nn][Oo]?)$  ]]  && echo “please input yes or

no”

配置文件总结

按生效范围划分,存在两类:

全局配置:

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

个人配置:

~/.bash_profile

~/.bashrc

/etc下的都是全局的

交互式登录:

(1)直接通过终端输入账号密码登录

(2)使用“ su – UserName” 切换的用户

执行顺序:/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile –>

~/.bashrc –> /etc/bashrc

非交互式登录:

(1)su UserName

(2)图形界面下打开的终端

(3)执行脚本

(4)任何其它的bash实例

执行顺序: ~/.bashrc –> /etc/bashrc –> /etc/profile.d/*.sh

注意:  一般脚本运行都是在子进程里运行

source + 脚本   这样是在当前shell运行,而不是在子进程里运行

注意:

1.设置文件写在~/.bashrc和/etc/profile.d/*.sh下则交互式登陆和非交互式登陆下都会执行但是为了保持系

统稳定性,一般推荐在/etc/profile.d/*.sh下建立。

2.脚本里不支持别名命令!!

例如直接写alias 都不支持

3.用户退出时的环境初始化也可以实现

.bash_logout

例如想实现退出后自动清空data下的文件

则可以把rm -rf /data/*写入.bash_logout这样就可以了.

4.$- 有特定的含义,代表功能的组合

默认显示himBH

h:代表哈希 hashall ,打开这个选项后,shell会将命令所在的路径hash下来,避免每次都要查询.

set +h 关闭选项

set -h 打开选项

i:interactive-comments,有这个选项说明当前shell是一个交互式的shell.

在脚本中,i选项是关闭的.

m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继

续,后台或者前台执行等。

B:braceexpand,大括号扩展

H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!” 返回上最近的一

个历史命令,“!n” 返回第 n 个历史命令

 

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/95936

(0)
MaxMax
上一篇 2018-04-14 17:04
下一篇 2018-04-14

相关推荐