shell编程

Posted liang-yao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell编程相关的知识,希望对你有一定的参考价值。

基础正则表达式

正则表达式和通配符

正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配。grep、awk、sed等命令可以支持正则表达式

通配符用来匹配符合条件的文件名,通配符是完全匹配。ls、find、cp这些命令不支持正则表达式,所以只能用shell自己的通配符来进行匹配

 

基础正则表达式

* 前一个字符匹配0次或任意多次
. 匹配除了换行符外任意一个字符
^ 匹配行首。如:^hello会匹配以hello开头的行
$ 匹配行尾。如:hello$会匹配以hello结尾的行
[] 匹配括号中指定的任意一个字符,只匹配一个字符。如:[0-9]匹配任意一位数字,[a-z][0-9]匹配小写字母和以为数字构成的两位字符
[^] 匹配除括号中的字符以外的任意一个字符。如:^[^0-9]匹配任意一位非数字字符
\ 转义符。用于取消特殊符号的含义
\{n\} 表示前面的字符恰好出现n次。如:[0-9]\{4\}匹配4位数字
\{n,\} 表示其前面的字符出校不下于n次。如:[0-9]\{2\}表示两位及以上的数字
\{n,m\} 表示其前面的字符至少出现n次,最多出现m次。如:[a-z]\{6,8\}匹配6到8位的小写字母

例:

 grep "a*" test_rule.txt

 

#匹配所有内容,包括空白行

 grep "aa*" test_rule.txt

#匹配至少包含一个a的行

 grep "a..f" test_rule.txt

#匹配在a和f之间有两个字符的单词

 grep "a.*g" test_rule.txt

#匹配在a和g之间有任意字符

 grep ".*" test_rule.txt

#匹配所有内容

grep -n "^$" test_rule.txt

#匹配空白行

 grep "\.$" test_rule.txt

#转义符  匹配以”.“结尾

 

字符截取命令

cut字段提取

  • -f: 提取第几列
  • -d: 按照指定分隔符分割列

例:

cut -d ":" -f 1,3,6 /etc/passwd

 

#查看用户名、用户UID、家目录

 cat /etc/passwd | grep /bin/bash | grep -v root |cut -d ":" -f 1

#提取出系统中能登录的用户。root除外

 

printf ‘输出类型输出格式’输出内容

输出类型:

%ns: 输出字符串。n是数字,指代几个字符

%ni: 输出整数。n是数字指代输出几个数字

%m.nf 输出浮点数,m和n是数字,指代输出的整数位数和小数位数。如%8.2f代表共输出8位数,其中两位是小数,6位是整数

输出格式:

  • \a: 输出警告音
  • \b: 输出退格键(backspace)
  • \f: 清除屏幕
  • \n: 换行
  • \r: 回车
  • \t: 水平输出退格键(tab)
  • \v: 垂直输出退格键(tab)

例:

printf ‘%s‘$(cat userdel.txt) 输出文件内容

 

 

在awk命令的输出中支持print和printf命令

print:会在每个输出之后自动加入一个换行符(Linux默认没有print命令)

printf:标准格式输出命令,并不会自动加入换行符,如果需要换行,需要手工加入换行符

 

awk ‘条件1{动作1} 条件2 {动作2}。。。’ 文件名

条件(pattern)

一般使用关系表达式作为条件

X>10 判断变量X是否大于10

X>=10 大于等于

X<=10 小于等于

动作(action)

格式化输出

流程控制语句

例子:

 awk ‘{printf $2 "\t" $4 "\n"}‘ student.txt

 

NAME    GENDER

小明    男

小红    女

小亮    男

 df -h | grep sda1 | awk ‘{print $5}‘|cut -d "%" -f 1

 

50

 

BEGIN

 awk ‘BEGIN{ printf "student\n"}{printf $2 "\t" $4 "\n"}‘ student.txt

 

student

NAME    GENDER

小明    男

小红    女

小亮    男

END

 awk ‘END{ printf "student\n"}{printf $2 "\t" $4 "\n"}‘ student.txt

 

FS内置变量:指定分隔符

例:

 awk ‘BEGIN{FS=":"}{print $1 "\t" $3}‘ /etc/passwd

 

cat /etc/passwd|grep /bin/bash |awk ‘{print $1 "\t" $3}‘

 

#显示所有可以登陆的用户

 

关系运算符

例:

 cat student.txt |grep -v ID|awk $3>=12 {print $2}‘

 

#筛选出第三列数字大于等于12 并把第二列的内容显示出来

 

sed:是一种几乎包括在所有Unix平台的轻量级流编辑器。sed主要用来将数据进行选取、替换、删除、新增的命令

 sed [选项] ‘[动作]‘ 文件名
  • -n: 一般sed命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕
  • -e: 允许对输入数据应用多条sed命令编辑
  • -i: 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出
  • 动作:
  • a \:追加,在当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾需要用“\”代表数据未完结
  • c \:行替换,在c后面的字符替换原数据行,替换多行时,除最后一行外,每行末尾需用“\”代表数据未完结
  • i \:插入,在行前插入一行或多行。插入多行时,除最后一行外,每行末尾需要用“\”代表数据未完结
  • d \:删除,删除指定的行
  • p \:打印,输出指定的行
  • s \:字符替换,用一个字符串替换另外一个字符串。格式为“行范围s/旧字串/新字串/g”

例:

  sed -n ‘1p‘ /etc/passwd #查看文件的第二行

 

sed ‘2,99d‘ /etc/passwd #删除2-99行的输出数据
sed ‘2a hello word‘ /etc/passwd #在第二行后追加数据
sed ‘2i hello word‘ student.txt #在第二行前插入数据
sed ‘s/14/99/g‘ student.txt #把student.txt中所有的14替换为99

 

sort 排序命令

-f 忽略大小写

-n 以数值型进行排序,默认使用字符串型排序

-r 反向排序

-t 指定分隔符,默认分隔符是制表符

-k n[,m] 按照指定字段范围排序。从第n字段开始,m字段结束(默认到行尾)

 

条件判断

两种判断格式:

 [ -d /etc ]&&echo yes ||echo no 
[ -e /etc/passwd ]

按文件类型进行判断

  • -d 判断该文件是否存在,并且是否为目录文件(是目录为真)
  • -e 判断该文件是否存在(存在为真)
  • -f 判断该文件是否存在,并且是否为普通文件(是普通文件为真)
  • -b 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真)
  • -c 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真)
  • -L 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真)
  • -p 判断该文件是否存在,并且是否为管道文件(是管道文件为真)
  • -s 判断该文件是否存在,并且是否为空(非空为真)
  • -S 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真)

 

按照文件权限进行判断

  • -r 判断该文件是否存在,并且该文件是否拥有读权限(有读权限为真)
  • -w 判断该文件是否存在,并且该文件是否拥有写权限(有写权限为真)
  • -x 判断该文件是否存在,并且该文件是否拥有执行权限(有执行权限为真)
  • -u 判断该文件是否存在,并且该文件是否拥有SUID权限(有SUID权限为真)
  • -g 判断该文件是否存在,并且该文件是否拥有SGID权限(有SGID权限为真)
  • -k 判断该文件是否存在,并且该文件是否拥有SBit权限(有SBit权限为真)

 

两个文件之间进行比较

文件1 -nt 文件2 判断文件1的修改时间是否比文件2的新(如果新则为真)

文件1 -ot 文件2 判断文件1的修改时间是否比文件2的旧(如果旧则为真)

文件1 -ef 文件2 判断文件1是否和文件2的INode号一致,可以理解两个文件是否为同一个文件。用于判断硬链接(ln创建硬链接)

 

两个整数之间的比较

整数1 -eq 整数2 判断整数1是否和整数2相等(相等为真)

整数1 -ne 整数2 判断整数1是否和整数2不等(不等为真)

整数1 -gt 整数2 判断整数1是否大于整数2(大于为真)

整数1 -lt 整数2 判断整数1是否小宇整数2(小于为真)

整数1 -ge 整数2 判断整数1是否大于等于整数2(大于等于为真)

整数1 -le 整数2 判断整数1是否小于等于整数2(小于等于为真)

 

字符串判断

-z 判断字符串是否为空(为空返回真)

-n 判断字符串是否非空(非空返回真)

字符串1 == 字符串2 判断字符号1是否和字符串2相等(相等返回真)

字符号1!=字符串2 判断字符串1是否和字符串2不等(不等返回真)

 

多重条件判断

判断1 -a 判断2 逻辑与,判断1和判断2都成立,最终的结果才为真

判断1 -o 判断2 逻辑或,判断1和判断2有一个成立,最终结果为真

! 判断 逻辑非,使原始的判断式取反

例:

 aa=22

 

[ -n "$aa" -a "$aa" -gt 23 ] && echo yes || echo no

 

#判断aa是否有值,同时判断aa是否大于23

#因为变量aa的值不大于23,所以虽然第一个判断值为真,返回的结果也是假

 

流程控制

单分支if条件语句

if [条件判断式]; then

程序

fi

if [条件判断式]

then

程序

fi

单分支条件语句需要注意几个点

if语句使用fi结尾,和一般语言使用大括号结尾不同

[条件判断式] 就是使用test命令判断,所以中括号和条件判断式之间必须有空格

then后面除符合条件之后执行的程序,可以放在[]之后,用“;”分割。也可以换行写入,就不需要“;”了

例:判断分区使用率

#!/bin/bash

 

 

diska=$(df -h | grep "/dev/sda3" | awk ‘{print $5}‘ | cut -d "%" -f1)

#把根分区使用率作为变量值赋予变量disk

 

 

if [ $diska -ge 80 ]

#判断变量diska是否大于80(大于等于为真)

then

echo "硬盘 /dev/sda3 剩余空间不足%20"

                df -h | grep "/dev/sda3"

        fi

 

双分支if条件语句

if [ 条件判断式 ]

then

条件成立时,执行的程序

else

条件不成立时,执行的另一个程序

fi

 

例:

#!/bin/bash

 

 

#mysql备份

#由于实验环境无mysql,则mysql路径/var/lib/mysql以/root代替

date=$(date +%y%m%d)

#把当前系统时间按年月日的格式赋予变量date

size=$(du -sh /root)

#统计MySQL大小并赋予变量size

 

if [ -d /tmp/backup ]

then

echo "$date" > /tmp/backup/backup-time.txt

echo "$size" >> /tmp/backup/backup-time.txt

cd /tmp/backup

tar czvf mysql-lib-$date.tar.gz  /root backup-time.txt&>/dev/null

rm -rf backup-time.txt

 

else

mkdir /tmp/backup

echo "$date" > /tmp/backup/backup-time.txt

echo "$size" >> /tmp/backup/backup-time.txt

cd /tmp/backup

tar czvf mysql-lib-$date.tar.gz  /root backup-time.txt&>/dev/null

rm -rf backup-time.txt

fi

 

 

例:判断apache是否启动

#!/bin/bash

 

 

 

port=$(nmap -sT 192.168.200.254 | grep tcp | grep http | awk ‘{print $2}‘)

#使用nmap扫描服务器端口,并截取apache服务的状态,赋予变量port

 

if [ "$port" == "open" ]

then

echo "$(date) running " >> /tmp/apache.log

else

systemctl start httpd.service

echo "$(date) restart " >> /tmp/apache.log

 

fi

 

多分支if条件语句

if [ 条件判断式1 ]

then

当条件判断式1成立,执行程序1

elif [ 条件判断式2 ]

then

当条件判断式2成立,执行程序2

.........................

else

当所有条件不成立,执行此程序

fi
判断用户输入文件类型

#!/bin/bash

 

#判断用户输入的文件类型

read -p "file name ?" file

#接受输入,并赋予变量file

 

if [ -z "$file" ]

#判断变量file是否为空

then

echo "ERROR 请输入文件名"

exit 1

 

elif [ ! -e "$file" ]

#判断file的值是否存在

then

echo "ERROR 请输入正确的文件名"

exit 2

elif [ -f "$file" ]

#判断file值是否为普通文件

then

echo "$file is ordinary file"

elif [ -d "file" ]

#判断file是否为目录文件

then

echo "$file is directory file"

else

echo "$file is other file"

fi

 

case语句

case $变量名 in

“值1”)

如果变量的值等于值1,则执行程序1

;;

“值2”)

如果变量的值等于值2,则执行程序2

;;

....................................

*)

如果变量的值都不是以上的值,则执行此程序

;;

esac

 

例:判断用户输入

#!/bin/bash

 

#判断用户输入

read -p "please choose yes/no:" -t 30 import

#如果30s未输入,则执行最后的 *)

case $import in

"yes")

echo "yes"

;;

"no")

echo "no"

;;

*)

echo "ERROR"

;;

esac

 

for循环

语法一

for 变量 in 值1 值2 值3...........

do

程序

done

 

例:

#!/bin/bash

 

 

for number in 1 2 3 4 5

do

echo "number is  $number"

done

 

 

例2:

#!/bin/bash

 

#批量备份脚本

 

cd /tar

ls *.tar.gz>tar.log

for t in $(cat tar.log)

do

tar xzvf $t &>/dev/null

done

rm -rf /tar/tar.log

 

 

for循环语法二

for ((初始值; 循环控制条件; 变量变化))

do

程序

done

 

例:

#!/bin/bash

 

#从1加到100

 

s=0

for ((i=1; i<=100;i=i+1))

do

s=$(($s+$i))

done

echo "$s"

 

 

例二:批量添加用户

#!/bin/bash

 

 

read -p " user name:" -t 30 name

read -p " user number:" -t 30 num

read -p " passwd:" -t 30 pass

 

if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass"  ]

then

 

y=$(echo $num | sed ‘s/^[0-9]*[0-9]‘//g)

if [ -z "$y" ]

#判断$num是不是数字

then

for (( i=1; i <= $num;i=i+1 ))

do

useradd $name$i &>/dev/null

echo $pass | passwd --stdin "$name$i" &>/dev/null

done

fi

fi

 

while循环

while循环是不定循环,也称作条件循环。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。这就和for的固定循环不太一样

while [条件判断式]

do

程序

done

 

例:从1加到100

#!/bin/bash

 

#从1加到100

 

i=1

s=0

while [ $i -le 100 ]

#如果变凉i的值小于等于100,则执行循环

do

s=$(( $s+$i ))

i=$(( $i+1 ))

done

echo "$s"

 

until循环

until循环,和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环

例:

#!/bin/bash

 

#从1加到100

 

i=1

s=0

 

until [ $i -gt 100 ]

#循环到变量的值大雨100,就停止循环

do

s=$(( $s+$i ))

i=$(( $i+1 ))

done

echo "$s"


以上是关于shell编程的主要内容,如果未能解决你的问题,请参考以下文章

代码片段:Shell脚本实现重复执行和多进程

Linux bash基础特性二

VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

使用 Pygments 检测代码片段的编程语言

面向面试编程代码片段之GC