shell脚本基础知识

shell脚本基础知识

头部声明规范

#!/bin/bash
#Author: wang
#Version: 1.0
#Date: 2016-05-01
#Description:The script displays system information
echo "Greetings. The date and time are $(date)"
echo "Your working directory is: $(pwd)"

bash

bash 和source执行脚本的区别

bash会开子shell执行,.和source会在当前shell执行

检测脚本中的语法错误bash -n /path/to/some_script

 调试执行bash -x /path/to/some_script\

显示没条命令的结果及层级

脚本终止

当出现语法错误时脚本会终止执行,命令错误还是继续执行

让脚本可执行

  1. 给执行权限
    1. 用bash目录执行
  2. 放在/bin/bash目录

显示环境变量

  • set(本地变量也会显示)
  • export
  • printenv

环境变量的声明

name='lee'
sex=male
export name sex # 或者用declare -x

常量的声明

name=lee
readonly name 或者declare -r name

变量生效范围

  1. ==环境变量只对但前shell及下级shell有效,不会影响父shell==
  2. ==unset的变量只对但前shell及下级shell有效,不会影响父shell==
  3. ==父shell声明export变量后再unset,再重新以普通变量赋值,则子shell不再继承此变量==
  4. == 常量在子shell内无效(readonly 和 declare -r)==

true 与false

为内建命令
false # ?=1  
! false  #?=0 (==!与false之间有空格,每空格是执行历史命令==)
[ false ] # $?=0

bash位置变量

删除位置变量
- set –(不可用unset)
- shift n 先进先出,从$1开始删(出栈)

bash中的算术运算

x=100
y=200
let z=$x+$y
let z=x+y
z=$[x+y]
z=$[$x+$y]
z=$((x+y))
z=$(($x+$y))

declare -i a=100 #声明int类型
declare -i b=200
declare -i c=a+b

==expr不能用来赋值,相当于计算器*需要转义==

增强型赋值(要用let赋值)

+=

-=

*=

/=

%=

:let count+=3(先增加3再赋值)

自增,自减:

  • let var+=1
  • let var++
  • let var-=1
  • let var–先减再赋值
  • let –var 先赋值再减

==判断参数是否处理完根据shift执行结果来判断.处理一个shift一个,当最后一个出理完再shift的时候会返回1,因为没有参数拿来处理了==

条件测试

  • test
  • [] ==[ ” ” ]==空字符串为真(变量未定义为假)
  • [[]] 特殊符号*等不用转义

字符串测试

| 变量 | 含义 |
| :—- | :—- |
== |是否等于;

|ascii 码是否大于ascii码 码
< | 是否小于
!= | 是否不等于
=~ |左侧字符串是否能够被右侧的PATTERN所 所 匹配
注意: 此表达式一般用于[[ ]] 中;扩展的正则表达式
[ -z x]−z如果为变量未定义返回真[−n“

x" ]或 [[ -n x]]未定义为真[[“

1" == "$USER” ]] ==注意等号两边有空格则是判断字符串相等,每空格则是判断是否非空==

[ " " ] 真
[ -z " " ]
[ "b" > "w" ] 正
[ "b" \> "w" ] 假
[ "btretr" \> "w" ] 假

== [] 里面用>要转义,字符串大小比较会以第一个字符的ascii码比较,符号字母直接要有空格;=~次符号两边不能有空格==

 数值测试

变量 含义
gt great than
lt lower than
eq equal
ne not equal
le lower equal
ge great equal

注意:须使用[[]]

#判断用户是否存在
 id user1 &> /dev/null && echo the user exist

练习

  1. 编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小。
 #!/bin/bash                                   ~                             
  8 echo -e "\033[35m主机名:\033[0m \033[36m `hos ~                             
    tname`\033[0m"                                ~                             
  9 sleep 2                                       ~                             
 10 echo -e "\033[35m系统版本:\033[0m \033[36m `u ~                             
    name -r`\033[0m"                              ~                             
 11 sleep 1                                       ~                             
 12 echo -e "\033[35mipv4地址:\033[0m \033[36m `i ~                             
    fconfig|grep -w inet|head -1|tr -s ' '|cut -d ~                             
    ' ' -f3`\033[0m"                              ~                             
 13 echo -e "\033[35m内核版本:\033[0m \033[36m `c ~                             
    at /etc/redhat-release`\033[0m"               ~                             
 14 sleep 1                                       ~                             
 15 echo -e "\033[35mCPU型号:\033[0m \033[36m `ls ~                             
    cpu| grep 'Model name'|cut -d: -f2|tr -s ' '` ~                             
    \033[0m"                                      ~                             
 16 sleep 1.5                                     ~                             
 17 echo -e "\033[35m硬盘空间:\033[0m \033[36m \n ~                             
    `df -h|grep -v 'tmpfs'`\033[0m"               ~                             
 18 sleep 1.5                                     ~                             
 19 echo -e "\033[35m内存大小:\033[0m \033[36m `f ~                             
    ree `\033[0m"
  1. 编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY-mm-dd中 中

  2. 编写脚本/root/bin/disk.sh, 显示当前硬盘分区中空间利用率最大的值

  3. 编写脚本/root/bin/links.sh, 显示正连接本主机的每个远程主机的IPv4

  4. 编写脚本/root/bin/sumid.sh ,计算/etc/passwd 文件中
    的第10 个用户和第20 用户的ID 之和

  5. 编写脚本/root/bin/sumspace.sh ,传递两个文件路径作
    为参数给脚本,计算这两个文件中所有空白行之和
  6. 编写脚本/root/bin/sumfile.sh,统计/etc,/var,/usr目录中共有多少个一级子目录和文件
  7.  
  8. 编写脚本/root/bin/argsnum.sh ,接受一个文件路径作为
    参数;如果参数个数小于1 ,则提示用户“至少应该给一个参
    数”,并立即退出;如果参数个数不小于1 ,则显示第一个参
    数所指向的文件中的空白行数

  9. 编写脚本/root/bin/hostping.sh ,接受一个主机的IPv4
    地址做为参数,测试是否可连通。如果能ping 通,则提示用户
    “该IP 地址可访问” ;如果不可ping 通,则提示用户“该IP地 地
    址不可访问”
     3 、编写脚本/root/bin/checkdisk.sh ,检查磁盘分区空间和inode使用率,如果超过80%,广播通知

存在性及类别测试

变量 含义
-a FIL 同-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 是否存在且非空
-t fd fd 表示文件描述符是否已经打开且与某终端相关
-N FILE 文件自上一次被读取之后是否被修改过
-O FILE 当前有效用户是否为文件属主
-G 当前有效用户是否为文件属组
-nt newer than, file1 比file2的mtime新
-ot file1比file2的mtile旧
-ef file1是file2的硬链接
lrwxrwxrwx.  1 root   root      7 Mar 21 16:42 lib -> usr/lib


ll -d /usr/lib
dr-xr-xr-x. 27 root root 4096 Mar 31 03:33 /usr/lib


[ -d /lib ] true
[989][root@yongge: /]# [ -L /lib ] true
[990][root@yongge: /]# [ -h /lib ] true
[991][root@yongge: /]# [ -b /lib ] false
==注意判断软连接时,会同时判断软连接和软连接指向的文件==

==权限是以最终权限为判据的==

判断权限之前先判断存在性

[ -e FILE -a -r FILE ]

()和{}中逻辑代码的区别

==()包含的逻辑代码会开子进程执行;{}包含的逻辑直接在父进程执行==
例如如下两个脚本:

# 脚本一
[ -e file1 ] || ( echo 'file1 not exit' && exit 2)
echo 'continue'

# 脚本2:
[ -e file1 ] || { echo 'file1 not exit' ; exit 2}
echo 'continue'

脚本一中遇到exit只是退出了子进程,所以echo continue会继续执行;脚本2中不会执行{}部分是一个匿名函数,故用分号隔开

双目测试

FILE1 -ef FILE2: FILE1 与FILE2 是否指向同一个设备上
的相同inode
FILE1 -nt FILE2: FILE1 是否新于FILE2
FILE1 -ot FILE2: FILE1 是否旧于FILE2

组合测试条件

- && || !

如:[[ -r FILE ]] && [[ -w FILE ]] 或者[ -r FILE -a -w FILE ]
- -a -o ! (不能使用[[]]进行测试)
[ ! -w /etc/passwd ] 不可写
[ -z “HOSTNAME”−o

HOSTNAME “==\
“localhost.localdomain” ] && hostname www.magedu.com
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab

设置颜色

格式 echo -e “\033[ 字背景颜色(40-47);文字颜色(30-37)m 字符串\033[0m”

Eg :echo -e “\033[41;36m something here \033[0m”
41 的位置代表底色, 36 的位置是代表字的颜色
字体颜色:30——37
echo -e “\033[30m 黑色字 \033[0m”
  echo -e “\033[31m 红色字 \033[0m”
  echo -e “\033[32m 绿色字 \033[0m”
  echo -e “\033[33m 黄色字 \033[0m”
  echo -e “\033[34m 蓝色字 \033[0m”
  echo -e “\033[35m 紫色字 \033[0m”
  echo -e “\033[36m 天蓝字 \033[0m”
  echo -e “\033[37m 白色字 \033[0m”
  

1. 编写脚本/bin/per.sh, 判断当前用户对指定的参数文件,
是否不可读并且不可写
2. 编写脚本/root/bin/excute.sh  ,判断参数文件是否为sh
后缀的普通文件,如果是,添加所有人可执行权限,否则提
示用户非脚本文件
3. 编写脚本/root/bin/nologin.sh 和login.sh, 实现禁止和充
许普通用户登录系统

参数替换和扩展

表达式 含义
varDEFAULT|如果var没有被声明,那么就以
DEFAULT作为其值 *  
var=DEFAULT|如果var没有被声明,那么就以
DEFAULT作为其值 *  
var:−DEFAULT|如果var没有被声明,或者其值为空,那么就以
DEFAULT作为其值 *  
var:=DEFAULT|如果var没有被声明,或者其值为空,那么就以
DEFAULT作为其值 *  
var+OTHER|如果var声明了,那么其值就是
OTHER, 否则就为null字符串  
var:+OTHER|如果var被设置了,那么其值就是
OTHER, 否则就为null字符串  
var?ERRMSG|如果var没被声明,那么就打印
ERR_MSG*  
var:?ERRMSG|如果var没被设置,那么就打印
ERR_MSG*  
${!varprefix*} 匹配之前所有以varprefix开头进行声明的变量
${!varprefix@} 匹配之前所有以varprefix开头进行声明的变量

字符串操作

表达式 含义
${#string} $string的 长度
${string:position} 在string中,从位置
position开始提取子串
${string:position:length} 在string中,从位置
position开始提取长度为$length的子串
${string#substring} 从 变量string的开头,删除最短匹配
substring的子串
${string##substring} 从 变量string的开头,删除最长匹配
substring的子串
${string%substring} 从 变量string的结尾,删除最短匹配
substring的子串
${string%%substring} 从 变量string的结尾,删除最长匹配
substring的子串
${string/substring/replacement} 使用replacement,来代替第一个匹配的
substring
${string//substring/replacement} 使 用replacement,代替所有匹配的
substring
${string/#substring/replacement} 如 果string的前缀匹配

substring, 那么就用replacement来代替匹配到的

substring
${string/%substring/replacement} 如果string的后缀匹配

substring, 那么就用replacement来代替匹配到的

substring
expr match "$string" '$substring' 匹配string开头的
substring* 的长度
expr "$string" : '$substring' 匹 配string开头的
substring* 的长度
expr index "$string" $substring 在string中匹配到的
substring的第一个字符出现的位置
expr substr $string $position $length 在string中从位置
position开始提取长度为$length的子串
expr match "$string" '\($substring\)' 从string的开头位置提取
substring*
expr "$string" : '\($substring\)' 从string的开头位置提取
substring*
expr match "$string" '.*\($substring\)' 从string的结尾提取
substring*
expr "$string" : '.*\($substring\)' 从string的结尾提取
substring*
s=www.baidu.www.com

# 删除指定字符(#从头开始匹配删,%从结尾开始匹配删)
echo ${s#w*}
ww.baidu.www.com

echo ${s##w*} #全部删除

echo ${s##*.}
com

echo ${s%.*}
www.baidu.www

echo ${s%%.*}
www

# 查找替换(支持通配符*?[])
echo ${s/www/ttt}
ttt.baidu.www.com

echo ${s/w/t}
tww.baidu.www.com

echo ${s//w/t}
ttt.baidu.ttt.com

echo ${s//*/t}
t

echo ${s//w*/t}
t


echo ${s//./t}
wwwtbaidutwwwtcom

echo ${s//\./t}
wwwtbaidutwwwtcom

echo ${s//w./t}
wwtbaidu.wwtcom

echo ${s/w./t}
wwtbaidu.www.com

echo ${s/w?/t}
tw.baidu.www.com

echo ${s//w?/t}
ttbaidu.ttcom

echo ${s/[a-z]/t}
tww.baidu.www.com

echo ${s//[a-z]/t}
ttt.ttttt.ttt.ttt

echo ${s/[^a-w]/t}
wwwtbaidu.www.com

echo ${s//[^a-w]/t}
wwwtbaidutwwwtcom


# 计算长度的2中方法:
echo ${#s}
17

expr length $s
17

# 获取包含字符在原串中的索引
expr index $s 'www' #获取www第一次出现的位置(从1开始)
1

==$substring是一个正 则表达式.==

长度计算

  • ${#var}
  • expr length var

截取

索引截取 ${var:index:length}

匹配截取

替换

  • 只替换第一个 ${var/reg/str}把reg匹配的部分替换成str
  • 全部替换 {var//reg/str}

删除

  • ${var%%reg}删除reg匹配的部分

变量容错

var=

{name-‘yongge’}若name不存在则把yongge赋值给name
var=

{name:=’yongge’}若name不存在或者为空则把yongge赋值给name

变量批量赋值

read x y z < /etc/issue

[root@yongge: /root]# read x y z <<<"111 222 333"
[root@yongge: /root]# echo $x
111
[root@yongge: /root]# echo $y
222
[root@yongge: /root]# echo $z
333


[root@yongge: /root]# read a b c <<<"$x $y $z"
[root@yongge: /root]# echo $a
111
[root@yongge: /root]# echo $b
222
[root@yongge: /root]# echo $c
333

bash命令执行顺序

  1. 把命令行分成单个命令词
  2. 展开别名
  3. 展开大括号种的声明({}) )
  4. 展开波浪符声明(~) )
  5. 命令替换$() 和 “) )
  6. 再次把命令行分成命令词
  7. 展开文件通配(* 、? 、[abc] 等等)
  8. 准备I/0 重导向(< 、>) )
  9. 运行命令

if语句

if condition;then
    action
fi

if contion
then
    action
fi

if condition1;then
    action1
else
    action2
fi


if condition1
then
    action1
else
    action2
fi

//多条件then不能换行写
if condition1;then
    action1
elif contion2;then
    action2
fi

if condition1;then
    action1
elif contion2;then
    action2
else
    action3
fi

for循环

for i in x;do
 action
done

for i;i<n;i++;do
    action
done

unit循环

unit condition;do
    action
done

select循环

select var in list
    do
        action
    done

while 语句

while i<n;do
    action
    let n--
done


while read line;do
    echo $line
done < /etc/passwd

function

语法-:
 function fname{

 }

语法二:

function fname(){

}

语法三:
fname(){

}

语法四:
{}

转载。https://blog.csdn.net/yonggeit/article/details/70214530

猜你喜欢

转载自blog.csdn.net/u010735147/article/details/81478733