目录
shell是核心程序kernel之外的指令解析器,是一个程序,同时是一种命令语言和程序设计语言。shell是命令解析器,用户输入命令,它去解析。
1 shell中的特殊字符
1.1 通配符
- * 用file_*.txt,匹配file_w.txt、file_l.txt;
- ? 用file_?.txt,匹配file_1.txt、file_2.txt、file_3.txt;<长度字符>
- [...] 用file_[orx].txt,匹配file_o.txt、file_r.txt、file_x.txt;
- [ - ] 用file_[a-z].txt,匹配file_a.txt、file_b.txt...file_z.tx;
- [^...] 用file_[^ort].txt,除了file_o.txt、file_r.txt、file_x.txt 的其他文件;
1.2 管道
管道可以把一系列命令连接起来,意味着第一个命令的输出将作为第二命令的输入,通过使用“|”连成一个管道;
comand1 | command2 //把一个命令command1执行结果作为command2的输入传给command2
ls | wc -w //查看文件的单词数
cat test.c | grep hello //输出test.c中hello
find ./ -name test -size +1k | xargs rm -rf
1.3 重定向
- command > file 把标准输出重定向到新文件中 ;ls > file,将ls的执行结果,写到file文件中,若同名文件将被删除;
- command >> file ls >> file,将ls的执行结果,追加到file文件中;
- command < file ls < file,将file中的内容作为输入传给命令ls;
- command &> flie ls 1.c &> file,ls命令,查看一个不存在的文件时,将系统错误提示信息存在file中;
- command <<delimiter 从标准输入中读入,直到遇到delimiter结束(把内容当作标准输入传给程序)
1.4 EOF与<<结合使用
EOF与 << 结合使用,表示后续的输入作为子命令或子Shell的输入,直到遇到EOF为止,再返回到主调Shell。
#向test.txt文件存入abcdef hello word ! 文本
cat >> test.txt << EOF
abcdef
hello word !
EOF
1.5 命令置换
命令置换:将一个命令的输出作为另一个命令的参数。
commad1 ·commad2· //命令comand2的输出将作为命令commad1的参数。
1.6 链接命令
ln -s 1.c link.c //软链接建立
ln 1.c lindk.c //硬链接建立
1.7 环境变量
1、PATH 和 HOME
echo $PATH #输出PATH环境变量
echo $HOME #s输出HOME环境变量
2、给环境变量追加内容: 格式 export PATH=$PATH:(增加的内容)
3、env 输出环境变量
env #输出所有环境变量
env $PATH #输出PATH环境变量
1.8 其他命令
1、alias --- 取别名(相当于C++中的引用)
alias ll=`ls -l` #ll就相当于ls -l
2、find用法:find + 路径 + 选项 + “查找内容”
find ./ -name "test*" //查找当前目录的test开头的文件
find ./ -nmae "[A-Z]*" //查找当前目录大写字母开头的文件
find ./ -nmae "[A-Z]*" -printf //查找当前目录大写字母开头的文件
find ./ -name "test" -tpye d//查找test目录
-type 查找某一类型的文件,诸如:
- b - 块设备文件。
- d - 目录。
- c - 字符设备文件。
- p - 管道文件。
- l - 符号链接文件。
- f - 普通文件。
2 shell编程
2.1 步骤
- 建立shell文件<注释用#>,vi test.sh
- 改变shell文件的执行权限,chmod +x test.sh
- 执行shell文件,./test.sh
2.2 shell变量
- Shell变量的最基本规则:变量只有字符串和整数两种类型。在shell运算中都是整数运算或字符串操作运算。
- 表达式运算,格式: $[表达式] 。 取值要加$, 赋值不要加$
- 表达式替换形式两种:$[表达式], $((表达式 ))
- 输出命令: echo 选项-e (常用)
- 输入命令:read 参数的使用规则 (常用)
- 输出命令:tee 用在管道相关的情况,调试时非常有用
#! /bin/sh
cout=1
echo $cout
echo ${cont} #和上面等价
echo $[cont] #和上面等价
name='xiaoming'
echo $name
set | grep cout #查看变量名和值,将输出num=5
- ${variablename} 显示实时值
- ${variablename:+value} 变量值为value
- ${variablename:?value} 如果变量定义了则值为之前的值。否则输出报错
- ${variablename:-value} 如果变量定义了则值为之前的值。否则值为value
- ${variablename:=value} 如果变量定义了则值为之前的值。否则值为value
#!/bin/bash
index=8
echo ${index:+"123"}
num=11
echo ${num:?"124"}
echo ${a:-"100"}
b=22
echo ${b:="200"}
- unset --- 取消变量
num=99
echo ${num}
unset num
echo ${num} #输出空
2.3 位置参数变量
- $0 脚本名称,echo $0 将在输出该脚本文件名;
- $1,$2,$3...$n 第一个到第n个命令行参数名;
- $# 命令行参数的个数;
- $* 参数列表;
- $@ 参数列表;
- $? 上一次执行的状态码;
- $$ 正在执行进程的ID号;
#! /bin/sh
echo $0
echo $#
echo $@
echo $*
echo $?
echo $$
注意:#!/bin/bash 表示根据这个得到解释器的类型,调用相对的解释器。
2.4 算数运算
expr <加(+)、减(-)、乘(\*)、整除(\)、求模(%) >
expr 12 + 5\*3 //27
num=9
sum=`expr $num / 6` #sum = 1
echo $sum
let用法
在shell中可以使用let来指示命令是算术表达式,let表达式内变量不用加$
num=9
let sum=9/6 #或者"sum=9/6"
echo $sum
2.5 test命令
- test语句可测试三种对象:字符串、整数、文件属性。真为0,假为1
- test -d name 测试name是否为一个目录;
- test -e name 测试一个文件是否存在;
- test -f name 测试那么是否为普通文件;
test -d test
echo $? #输出结果
2.6 整数测试
- $a -eq $b 测试a与b是否相等真为0,假为1
- $a -ne $b !=
- $a -gt $b >
- $a -ge $b >=
- $a -lt $b <
- $a -le $b <=
a=9
b=9
test $a -eq $b
echo $? #输出0
2.7 字符串
2.7.1 字符串比较
- “=” 相等<真为0,假为1>;
- “!=”不等;
- “- n” 判断是否为空;
- “- z” 长度为0;
- “\>”、“\<” 大于小于;
#!/bin/sh
str1="xiaoming"
str2="xiaohong"
if [ $str1 = $str2 ] #[等价] if [ "$str1"="$str2" ]两边要有空格,
then echo "="
else echo "!="
fi
if [ ${str1}\>${str2} ] #等价 if test $str1\>$str2
then echo ">"
else echo "<"
fi
if [ -n $str1 ]
then echo "1111"
else echo "0000"
fi
if [ -z $str1i ]
then echo "2222"
else echo "0000"
fi
2.7.2 字符串截取、替换和删除
- 截取 :
- 替换 /
- 删除左边 #
- 删除右边 %
例:dome="wang.csdn.net"
- ${demo:2:3} #从第2字符开始取3个字符,ng.c
- ${demo:2} #从第0字符开始取2个字符,wa
- ${demo:0-3} #取倒数2个字符,net
- ${demo/wang/good} #将wang替换为good
- ${demo/./-} #替换第一个点(".")-首次匹配,wang-csdn.net
- ${demo//./-} #贪婪模式,替换所有点("."),wang-csdn-net
- ${demo#*.} #从左删除首次匹配部分.的左边所有内容包括.,csdn.net
- ${demo##*.} #贪婪模式,从左删除所有匹配部分,net
- ${demo%.*} #从右边删除首次匹配的部分.*,wang.csdn
- ${demo%%.*} #贪婪模式,从右删除所有匹配部分.*,wang
2.8 条件语句(if...then...fi)
格式:
1、if [ 表达式 ] //[]两边有空格
2、if test 表达式1 选项 表达式2
3、if test 选项 表达式
1、if...then...fi
if 表达式
then 命令表
fi
2、if...then...else...fi
if 表达式
then 命令表1
else 命令表2
fi
3、if...then...elif then...esle...fi
- 例1:比较两个数是否相等
a=9
b=8
if test $a -eq $b
then echo $a
else echo $b
fi
- 例2:查看某个文件是否存在
#! /bin/sh
FILENAME="/usr/test1.txt"
if [ -f $FILENAME ]
then echo "yes"
else echo "NO"
fi
- 例3:查看多个文件是否存在
#! /bin/bash
OBJPATH="root/domo";
TEST="test.txt";
INFO="info.txt";
if [ -f "$OBJPATH/$TEST" -a -f "$OBJPATH/$INFO" ]
then
echo "file all exist"
else
echo "file no exist"
fi
- 例4:
#!/bin/bash
count=3
num=4
if [[ $count == 0 ]] && [[ $num == 0 ]];then
echo "[1].count=$count,num=$num"
elif [[ $count == 2 ]] && [[ $num == 2 ]];then
echo "[2].count=$count,num=$num"
elif [[ $count > 3 ]] && [[ $num > 3 ]];then
echo "[4].count=$count,num=$num"
else
echo "[5].count=$count,num=$num"
fi
2.9 多路分支语句
case $_ in
模式1)
命令表1
;;
模式2)
命令表2
;;
模式n)
命令表 n
;;
esac
a=2
case $a in
1)
echo xiaoming
;;
2|8)#2或8
echo xiaohong
;;
esac
#!/bin/sh
char='b'
case $char in
a)
echo xiaoming
;;
b|B)
echo xiaohong
;;
esac
2.10 循环语句
1、for循环
for...do...done
for 变量名 in 单词表
do
命令表
done
for num in 1 2 3 4 5
do
echo "hello $num"
done
//打印出
hello 1
hello 2
hello 3
hello 4
hello 5
for((num=1;num<=5;num++))
do
echo "hello $num"
done
2、while循环
while...do...done
while 命令式表达式
do
命令表
done
num=1
while test $num -lt 5
do
echo "num=$num"
num=`expr $num + 1`
done
read num #相当于C中scanf
while test $num -lt 5
do
echo "num=$num"
num=`expr $num + 1`
done
while((num<=5))
do
echo "num=$num"
num=`expr $num + 1`
done
死循环
##方法1:
while :
do
#内容
done
##方法2:
while true
do
#内容
done
(十)break 和 continue
for num in 1 2 3 4 5
do
if test $num -eq 2
then break
fi
echo "hello $num"
done
2.11 shell函数
函数名称在当前脚本必须唯一,如果存在相同名称的函数,以最后一个为准。
函数的创建方法一:
function 函数名称 {
命令
}
函数的创建方法二:
函数名称() {
命令
}
函数的调用方法:
函数名称 参数1 参数2 ...
调用函数时可以传递参数,函数中使用$1、$2......来引用传递的参数。
function fun()
{
echo "hello word!"
}
fun
function fun()
{
echo "hello word!"
echo $1
}
fun 12
function fun()
{
echo "hello word!"
return 43
echo $1
}
fun 12
echo $?
2.12 判断文件夹或文件是否存在
-e 判断对象是否存在
-d 判断对象是否存在,并且为目录
-f 判断对象是否存在,并且为常规文件
-L 判断对象是否存在,并且为符号链接
-h 判断对象是否存在,并且为软链接
-s 判断对象是否存在,并且长度不为0
-r 判断对象是否存在,并且可读
-w 判断对象是否存在,并且可写
-x 判断对象是否存在,并且可执行
-O 判断对象是否存在,并且属于当前用户
-G 判断对象是否存在,并且属于当前用户组
-nt 判断file1是否比file2新 [
"/data/file1"
-nt
"/data/file2"
]
-ot 判断file1是否比file2旧 [
"/data/file1"
-ot
"/data/file2"
]
- 查看某个文件是否存在
#! /bin/sh
FILENAME="/usr/test1.txt"
if [ -f $FILENAME ]
then echo "yes"
else echo "NO"
fi
- 查看文件是否存在
#! /bin/sh
FILENAME="/usr/test1.txt"
if [ ! -f $FILENAME ]
then echo "NO"
else echo "YES"
fi
- 查看多个文件是否存在
#! /bin/bash
OBJPATH="root/domo";
TEST="test.txt";
INFO="info.txt";
if [ -f "$OBJPATH/$TEST" -a -f "$OBJPATH/$INFO" ]
then
echo "file all exist"
else
echo "file no exist"
fi
- 查看文件夹是否存在
#! /bin/bash
OBJPATH="root/domo";
if [ -d "$OBJPATH" ]
then
echo "file all exist"
else
echo "file no exist"
fi
2.13 获取文件内容
方法一:
#! /bin/bash
fileName="/root/dome/test.txt"
while read line
do
echo $line
done < $fileName
方法二:
#! /bin/bash
fileName="/root/dome/test.txt"
cat $fileName | while read line
do
echo $line
done
2.14 等待(slepp)
sleep 10 #休眠10s(可用小数)
usleep 1000 #休眠1000毫秒
2.15 查看某个进程是否存在
查看某个进度是否存在,不存在则拉起(相当于守护进程)
#!/bin/bash
DIR=/root/work/demo
NAME=test #可执行文件
while :
do
count=`ps -ef | grep $NAME | grep -v "grep" | wc -l`
echo $count
if [[ $count == 0 ]];then
${DIR}/${NAME}
else
sleep 5
fi
done
命令:"ps -ef | grep test | grep -v grep | wc -l",各子命令其作用如下
- ps -ef 指令用来查询所有进程;"-e" 参数代表显示所有进程,"-f" 参数代表全格式;
- grep test 通过管道来过滤指定 test进程;
- grep -v 是反向查询的意思,即过滤出不包含 -v 参数后指定字符的信息;
- grep -v grep 的作用是即反向过滤除结果集中包含 grep 的项;grep test这个命令过滤进程,该命令本身执行的时候也是一个进程,并也带有 test 关键字,会出现在最后输出的进程信息里;所以需要 -v grep 过滤;
- wc -l 是统计结果的行数。
2.16 获取某个进程的内存占用和CPC占用率
#!/bin/bash
pid=` ps -A | grep$1 | grep -v grep | awk '{print $2}' ` #$1是脚本的参数(进程名)
echo $pid
while true
do
echo -en "`date'+%Y-%m-%d %H:%M:%S'`" >>$1_memlog.txt #时间
echo -en "\t`cat/proc/$pid/status|grep -e VmRSS`" >> $1_memlog.txt #获取内存占用
echo -en "\t\t`ps -eo comm,pcpu |grep $1`\r\n" >> $1_memlog.txt #CPU占用率
sleep 1
done
命令解析
(1) date '+%Y-%m-%d %H:%M:%S'【获取系统时间】
(2) ps -A | grep $1 | grep -v grep | awk awk '{print $2}' 【获取进程号】
- ps -A 指令用来查询所有进程
- grep $1 通过管道来过滤指定进程,$1是脚本的参数即进程名;
- grep -v 是反向查询的意思,即过滤出不包含 -v 参数后指定字符的信息;
- grep -v grep 的作用是即反向过滤除结果集中包含 grep 的项;grep $1这个命令过滤进程,该命令本身执行的时候也是一个进程,并也带有 $1 关键字,会出现在最后输出的进程信息里;所以需要 -v grep 过滤;
- awk '{print $2}' 输出每行的2列内容,注意:这里要根据实际情况更改,不同系统的列不同
(3) cat /proc/$pid/status|grep -e VmRSS 【输出某进程的内存占用大小】
- /proc/$pid/status 在Linux中,用户进程在/proc/{pid}/status文件中记录了该进程的内存使用实时情况。
-
- VmSize:虚拟内存大小;整个进程使用虚拟内存大小,是VmLib, VmExe, VmData, 和 VmStk的总和。
- VmLck:虚拟内存锁;进程当前使用的并且加锁的虚拟内存总数。
- VmRSS:虚拟内存驻留集合大小;这是驻留在物理内存的一部分,它没有交换到硬盘。它包括代码,数据和栈。
- VmData:虚拟内存数据;堆使用的虚拟内存。
- VmStk:虚拟内存栈;栈使用的虚拟内存。
- VmExe:可执行的虚拟内存;可执行的和静态链接库所使用的虚拟内存;
- VmLib:虚拟内存库;
(4) ps -eocomm,pcpu 【显示所有命令占用的cpu的大小】
2.17 输出到文件
1、输出时间
#!/bin/bash
LOGPATH=/root/work/demo/test.log
count=3
while true
do
time=$(date "+%Y-%m-%d %H:%M:%S.%N")
echo "[$time] count = $count">> $LOGPATH
sleep 1
done
#[2023-01-02 20:14:14.376715912] count = 3
#[2023-01-02 20:14:15.378973923] count = 3
#[2023-01-02 20:14:16.381747673] count = 3
#[2023-01-02 20:14:17.384710116] count = 3
#[2023-01-02 20:14:18.386843804] count = 3
2、输出进程号
#!/bin/bash
LOGPATH=/root/work/demo/test.log
APP=test_wl #进程名
while true
do
############方法一##############
time=$(date "+%Y-%m-%d %H:%M:%S.%N")
echo "[$time] APP pid:$(pidof $APP)">> $LOGPATH #若有多个进程,会输出所有进程号
############方法二##############
pidArray=`ps -A | grep $APP | grep -v grep | awk '{print $1}'` #若有多个进程,pidArray相当于数组
#pidList=(${pidArray}) #有些系统需要强转
time=$(date "+%Y-%m-%d %H:%M:%S.%N")
echo "[$time] APP pid:$pidArray">> $LOGPATH
sleep 1
done
2.18 自增(i++)自减(i--)
#!/bin/bash
i=0
#方式一:
i=$(($i+1))
echo "1. i = $i"
#方式二:
i=$[$i+1]
echo "2. i = $i"
#方式三:
i=`expr $i + 1`
echo "3. i = $i"
#方式四:
let i++
echo "4. i = $i"
#方式五:
let i+=1
echo "5. i = $i"
#i--,把+改-