目录
一.shell概述
1.概述
shell是一个用于用户和LInux系统之间交互的命令解释器
shell有两种模式:
交互式:用户输入一条命令,shell就解释执行一条。
非交互式:用户事先写一个shell脚本,其中有很多条命令,让shell一次把这些命令执行完,而不是一条一条地敲命令
2.使用方法
- vim xx.sh
- 在第一行输入#!/bin/bash //声明shell类型 bash shell,可以省略不写。
- 编写命令 保存退出
- 使用chmod 可执行权限 (可以bash xx.sh 不需要更改权限)
- 运行./xx.sh 或 bash xx.sh
- #为注释
二.shell语法
$使用:${}--取变量内容 $()--取命令执行结果 $[] 或者$(())--算数运算
1.shell变量
1)局部变量
shell脚本内定义的变量默认是全局变量,如果只想在某个函数内部使用,添加关键词local
2)全局变量(可以在当前shell进程中使用)
变量定义:test=aaa
变量赋值:test=bbb
变量追加 : test+=ccc //bbbccc
变量拼接:test=${test}.ddd
变量使用:echo ${test} 或 echo $test
清空变量:unset test
变量第一次出现是定义,之后是变量的赋值
3)环境变量 (可以在shell子进程中使用)
环境变量 :操作系统运行必要的变量,在操作系统开机时就已经定义好了。对所有的shell都生效。
用 echo $PWD 显示,
用 env 查看所有环境变量,
用 env | grep "name"查找指定环境变量。
用"export"进行设定或更改为环境变量
修改环境变量:export PATH=$PATH:/root //将root用户添加PATH环境变量里,重启后失效(PATH内保存的是bin目录--用户命令)
注意:不同的终端拥有各自独立的环境变量,shell变量不需要先定义,随用随定,初始化不赋值默认为空字符串。
单引号:括字符串——不能展开变量
双引号:括字符串——可以将变量展开 建议,在取变量值时,都加""
2.字符替换、命令替换、算术代码和转义字符
字符替换:
*:匹配0个或多个任意字符 *.sh
?:一个?代表匹配一个字符
[]:匹配任意一个字符 [a-z][0-9].sh 其中数字只能匹配单个【0-9】,如果想匹配多位数【1-3】【0-9】= 10-39
命令替换:
test=$(data) 或 test=`data` ESC下面的反单引号
算术代码:
$((变量名)) :对变量执行算数运算
$[变量名] :对变量执行算数运算
示例:$((VAR+10)) 或 $[VAR+10]
注意:只能进行整数运算
转义字符:
’\’在Shell中被用作转义字符,用于去除紧跟其后的单个字符的特殊意义(回车除外)
3.位置参数和特殊变量
$0 | 相当于argc[0],对于shell来说永远都是shell脚本 |
$1 $2.. | 相当于传参的argc[1] argc[2].... |
$# | 相当于argv-1 传参个数 |
$@=$* | 表示参数列表所有值 |
$? | 上一条命令执行完后的 结果存放在此 |
$$ | 当前进程号 |
4.输入和输出
输入:read test
输出:echo [opt] string
-e:解析转义字符
-n:不回车换行 echo默认回车换行
5.条件判断表达式(真:0;假:1)
大于 | -gt(greater than) |
大于等于 | -ge(greater equal) |
小于 | -lt(less than) |
小于等于 | -le(less equal) |
等于 | -eq(equal) |
不能等于 | -ne(not equal) |
如果DIR存在并且是一个目录则为真 | [ -d DIR ] |
如果FILE存在并且是一个普通文件则为真 | [ -f FILE ] |
判断文件是否存在,如果存在则为真 | [ -e FILE ] |
如果STR的长度为0则为真 | [ -z STR ] |
如果STR的长度非0则为真 | [ -n STR ] |
如果俩个字符串相同则为真 | [ str1 = str2 ] |
如果字符串不相同则为真 | [ str1 != str2 ] |
注:只要涉及条件表达式各个符号之间一定要有空格
6.逻辑运算
-a :逻辑与
-o:逻辑或
!:逻辑非
优先级:非 > 或 > 与
7.条件语句
1)if分支语句
if [ 条件 ];then
执行内容
fi
if [ 条件 ]
then
执行内容
fi
if [ 条件 ]
then
执行内容
elif [ 条件 ]
then
执行内容
else
执行内容
fi
#!/bin/bash
echo "请输入你要判别的文件名"
read file_name
if [ -f $file_name ];then
echo "It is a file"
elif [ -d $file_name ];then
echo "It is a dir"
else
echo "It is not a know file"
fi
2)case分支语句
case &变量 in
case1)
执行语句;;
case2)
执行语句;;
.......
*)
执行语句;;
esac
#!/bin/bash
read score
case ${score} in
0|60)
echo "0或者60";; //0或者60
[6-8][0-9])
echo "合格";; //60-89
[9][0-9]|100)
echo "优秀";; //90-99 100
esac
#!/bin/bash
echo "Is it morning? Please answer yes or no."
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES)
echo "Good Morning!"
echo "Good Morning!"
echo "Good Morning!;;
[nN][Oo])
echo "Good Afternoon!";;
*)
echo "Sorry,$YES_OR_NO not recognized.Enter yes or no";;
esac
8.循环语句
1)for循环语句(6种模型)
Shell脚本中的for循环还可以实现在列表中循环一遍(遍历列表)。从这个列表中拿值
语法循环 for((i=0;i<5;i++)) do 执行内容 done | 有限数字 #!/bin/bash for A in 1 2 3 4 5 6 do echo $A done
|
命令结果$ #!/bin/bash IFS=$`\n` for A in $(cat ./2.sh) #取命令执行结果作为集合 do echo $A done | 序列数据 #!/bin/bash for A in $(seq 1 1 10) #取命令执行结果作为集合 do echo $A done |
集合:{}表示一个连续序列 #!/bin/bash for A in {a..z} do echo $A done | 变量作为集合 #!/bin/bash buff="1 2 3 4 5 6 7 8 9" for A in $buff do echo $A done |
求1-100和
#!/bin/bash
sum=0
for i in $(seq 1 100)
do
sum=$((sum+i))
if [ ${i} -eq 100 ];then
echo "${sum}"
exit 0
fi
done
#!/bin/bash
for FRUIT in apple banana pear;do
echo "I like $FRUIT"
done
2)while循环语句
while [ 循环条件 ] do 执行内容 done |
#!/bin/bash
echo "Enter password:"
read TRY
while [ "$TRY" != "123123" ];do
echo "Sorry,try again"
read TRY
done
9.控制语句
break :可以跳出循环;
continue:跳过本次循环,但不会跳出循环。
exit:结束本程序,结束进程
10.数组
数组定义:a=(1 2 3 4 5) 或者 a[0]=1;a[1]=2;a[2]=3;
数组引用:${a[下标]}
数组长度:${#a[@]} 或 ${#a[*]}
#!/bin/bash
a=(3 10 6 5 9 2 8 1 4 7)
i=0
echo ${#a[*]}
while [ $i -lt 10 ] #类似C语言的写法
do
echo ${a[$i]}
i=$((i+1))
done
11.函数
函数名() { 函数体 } function 函数名() { 函数体 } 参数:函数外:$0--命令行参数argc[0] $1-$N--命令行参数的argc[1]-argc[N] 函数内: $0--命令行参数argc[0] $1-$N--函数的参数1--参数N 返回值:用$?接收 只能返回某个0-255之间的整数值 调用:函数名即可,不加括号 |
#!/bin/bash
A=$1
B=$2
add()
{
return $((A+B))
}
sub()
{
return $((A-B))
}
mul()
{
return $((A*B))
}
div()
{
return $((A/B))
}
//add 2 1 脚本内传参
add
echo $?
sub
echo $?
mul
echo $?
div
echo $?
注:函数定义必须在调用之前,且不能声明
12.shell调试
-n | 读一遍脚本中的命令但不执行,用于检查脚本中的语法错误 |
-v | 一边执行脚本,一边将执行过的脚本命令打印到标准错误输出 |
-x | 提供跟踪执行信息,将执行的每一条命令和结果依次打印出来 |
调试模板:sh -x 可执行文件
如果出现无反应问题:代码对于标准bash而言没有错,因为Ubuntu/Debian为了加快开机速度,用dash代替了传统的bash,是dash在捣鬼,解决方法就是取消dash。
sudo dpkg-reconfigure dash
选择项中选No,搞定了!
-n示例:
#!/bin/bash #:#代表注释功能 #IFS说明:bash shell 会将空格、制表符、换行当做分隔符 #定义该函数 先定义再调用 function func(){ echo "我是func函数" echo "函数体内参数0为$0" echo "函数体内参数1为$1" echo "函数体内参数2为$2" echo "函数体内参数3为$3" return xyd } #调用函数 A=$(func one two three) echo "A结果${A}" echo "./1.sh参数0为$0" echo "./1.sh参数1为$1" echo "./1.sh参数2为$2" echo "./1.sh参数3为$3" if["xyd"="xyd"];then echo "xyd" fi echo "结束" 效果: |
-v调试
#!/bin/bash #:#代表注释功能 #IFS说明:bash shell 会将空格、制表符、换行当做分隔符 #定义该函数 先定义再调用 function func(){ echo "我是func函数" echo "函数体内参数0为$0" echo "函数体内参数1为$1" echo "函数体内参数2为$2" echo "函数体内参数3为$3" return xyd } #调用函数 A=$(func one two three) echo "A结果${A}" echo "./1.sh参数0为$0" echo "./1.sh参数1为$1" echo "./1.sh参数2为$2" echo "./1.sh参数3为$3"
if [ "xyd" = "xyd" ];then echo "xyd" fi echo "结束" 效果:
|
三.正则表达式
1.grep与find命令
1)grep
grep是一个强大的文本搜索器。grep命令用于在指定文件中搜索包含与给定PATTERN匹配的行。如果gerep未指定文件或者为-,则grep指令会从标准输入设备读取数据。默认情况下,grep打印的是符合条件所在的行。默认下grep使用的是基础正则表达式,使用egrep或grep -E指定的是扩展正则表达式。
grep家族有:grep、egrep、fgrep。egrep、fgrep分别与grep –E(扩展正则表达式) rep -r相同。
常用格式:grep [OPTIONS] PATTERN [FILE]
--help:获取更多信息。
-i:不区分大小写。
-n:显示匹配行及行号。
-v:显示不包含匹配文本的所有行。
-c:只输出匹配行的计数。不打印行内容打印行号
-o:只显示被模式匹配到的字符串。打印想要的内容,可能对打出涵盖单词的字符串
-w:被匹配的文本只能是单词,而不能是单词中的某一部分。只打印想要的内容
-E :开启扩展(Extend)的正则表达式。
-h:查询多文件时不显示文件名。
-l:查询多文件时只输出包含匹配字符的文件名。
-L:查询多文件时只输出不包含匹配字符的文件名。
-A n:显示匹配到的字符串所在的行及其后n行,after
-B n:显示匹配到的字符串所在的行及其前n行,before
-C n:显示匹配到的字符串所在的行及其前后各n行,context
2)find
find 命令用来在指定目录下查找文件,并且搜索完成后可以执行相应的操作,搜索时我们可以根据参数指定相应的搜索条件,比如按文件名,文件类型,时间戳等。find命令的基本格式如下所示:
常用格式:find [path] [option] [expression]
注:如果使用find命令不设置任何参数,则find命令将在当前目录下查找子目录和文件,并打印
根据文件名字查找文件: -name | |
# find ./ -name "testfile" #查找名字为testfile的文件 # find ./ -iname "testfile" #查找名字为testfile的文件,忽略大小写 # find ./ -name "*.c" #查找名字以“.c |
根据文件大小查找文件: -size | |
# find ./ -size 5c #查找文件大小为5个字节的文件 # find ./ -size +5k #查找文件大小大于5KB的文件 # find ./ -size -5M #查找文件大小小于5MB的文件 # find ./ -size +5G -size -10G #查找文件大于5GB小于10GB的文件 |
文件类型查找文件: -type find ./ -type f | |
f:普通文件 d:目录文件 l:链接文件 p:管道文件 b:块设备文件 c:字符设备文件 s:套接字文件
|
限制目录查找深度: -maxdepth | |
find命令默认会递归查找整个目录树 # find ./ -maxdepth 2 -type d #在两层以内的子目录中查找文件类型为目录文件的文件 |
查找到的文件执行命令:-exec|-ok | |
find ./ -maxdepth 2 -tpye d -exec ls -l {} \;表示结束 固定格式 find -maxdepth 1 -type f | -ok ls -l {} \; |
根据时间查找文件: -atime|-mtime|-ctime|-amin|-mmin|-cmin | |
atime:访问时间(access time),指的是文件内容最后被访问的时间,单位为天。 mtime:修改时间(modify time),指的是文件内容最后被修改的时间,单位为天。 ctime:变更时间(change time),指的是文件本身最后被变更的时间,这个变更是指文件内容发生修改或者文件权限,路径发生改变,单位为天。 amin|mmin|cmin:单位为分钟 # find ./ -mtime -3 #查找三天内修改过的文件 # find ./ -atime 3 #查找过去的第三天被修改的文件 # find ./ -mtime +3 #查找三天前修改过的文件 |
文件权限查找文件: -perm | |
# find ./ -perm 0644 #查找文件权限为0644的文件 # find ./ -perm -0644 #查找文件权限至少是0644的文件 # find ./ -perm /0644 #查找文件权限至少是0644中的一种权限的文件。 | |
根据文件属主查找文件: -user | |
# find ./ -user root #查找文件属主为root的文件 | |
根据文件属组查找文件: -group | |
# find ./ -group root #查找文件属组为root的文件 |
3)正则表达式命令
正则表达式分为基础正则表达式和扩展正则表达式。
正则表达式是对普通字符和特殊字符(元字符)操作的一种逻辑公式。就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串。
元素种类 | 元字符 | 元字符功能 |
字符匹配 | . | 匹配任意字符 |
[] | 两者连用表示取序集 【a-zA-Z0-9】 | |
- | ||
^ | 放在【】里,表示取除了括号内的任意字符’ | |
\ | 转义 | |
次数匹配 | ? | 表示匹配?前面单元0或1次 egrep "12?" 2.txt :匹配的是1或者2或者12 egrep "(12)?" 2.txt:匹配的是12 |
+ | 匹配前面单元1次或者多次 | |
* | 匹配前面单元0次或者多次 | |
{N} | 匹配前面单元N次 | |
{,M} | 匹配前面单元最多M次 | |
{N,M} | 匹配前面单元最少N次,最多M次 | |
位置铆定
| ^ | 匹配行首位置,放在正则表达式开头 |
$ | 匹配行尾位置,放在正则表达式结尾 | |
\<匹配单词开头的位置
root@turbo:/home/xyd/study/Regular# egrep "\<a" 2.txt | ||
\b | 匹配单词开头或结尾的位置 root@turbo:/home/xyd/study/Regular# egrep "a\b" 2.txt | |
\B | 根据\B的位置去匹配非单词开头或结尾的位置,如果放在正则表达式开头,就是非开头,却不包括结尾。 root@turbo:/home/xyd/study/Regular# egrep "\Ba" 2.txt | |
() | 括号匹配的是一个单元 | |
匹配汉字 | grep -P "[\p{Han}]" text.c egrep "[\u4e00-\u9fa5]+ [\u4e00-\u9fa5]*" "1.txt" |
[[:alpha:]] | :匹配任意大小写字母 egrep [[:alpha:]] 2.txt |
[[:alnum:]]: | 匹配字母与数字 |
[[:upper:]]: | 匹配任意大写字母 |
[[:space:]]: | 匹配空格 |
[[:digit:]]: | 匹配十进制数字 |
[[:punct:]]: | 匹配标点符号 |
4)C语言正则表达式
C语言正则表达式常用的函数有regcomp(),regexec(),regfree(),regerror()
大题流程:regcomp编译正则表达式,regexec匹配正则表达式,regfree()释放正则表达式
int regcomp(regex_t *preg,const char *regec,int cflags)
功能:把指定的正则表达式pattern编译成一种特定的数据格式preg,这样可以使匹配更有效。
参数:
preg: 用来存放编译后的正则表达式
regex: 指向我们写好的正则表达式
cflags:有如下4个值或者是它们或运算(|)后的值
REG_EXTENDED--以功能更加强大的扩展正则表达式的方式进行匹配。
REG_ICASE-----匹配字母时忽略大小写。
REG_NOSUB-----不用存储匹配后的结果。
REG_NEWLINE---识别换行符,这样'$'就可以从行尾开始匹配,'^'就可以从行的开头开始匹配返回值:成功返回0,失败返回错误码
int regexec(const regex_t *preg,const char *string,size_t nmatch,regmath_t pmatch[],int eflags)
功能:接收匹配得到的数据。
例如:如果nmatch给定长度为2,那么regmatch_t 就是两个结构体数组。第一个结构体数组存放第一个匹配成功字符串信息。第
二个返回第二个匹配成功字符串信息。参数:
preg: 是已经用regcomp函数编译好的正则表达式
string:是目标文本串
nmatch:是regmatch_t结构体数组的长度
pmatch:regmatch_t类型的结构体数组,存放匹配文本串的位置信息
eflags:有两个值
REG_NOTBOL:让特殊字符^无作用
REG_NOTEOL:让特殊字符$无作用
返回值:成功返回0,失败返回REG_NOMATCHtypedef struct {
regoff_t rm_so; //存放匹配文本串在目标串中的开始位置
regoff_t rm_eo; //存放匹配文本串在目标串中的结束位置
} regmatch_t;
void regfree(regex_t *preg)
功能: 当我们使用完编译好的正则表达式后,或者要重新编译其他正则表达式的时候,我们可以用这个函数清空compiled指向的
regex_t结构体的内容, 请记住,如果是重新编译的话,一定要先清空regex_t结构体。
preg: 是已经用regcomp函数编译好的正则表达式
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
功能:当执行regcomp 或者regexec 产生错误的时候,就可以调用这个函数而返回一个包含错误信息的字符串
参数:
errcode:是由regcomp 和 regexec 函数返回的错误代号。
preg: 是已经用regcomp函数编译好的正则表达式,这个值可以为NULL。
errbuf: 指向用来存放错误信息的字符串的内存空间。
errbuf_size:指明buffer的长度,
注:如果这个错误信息的长度大于这个值,则regerror 函数会自动截断超出的字符串,
但他仍然会返回完整的字符串的长度。所以我们可以用如下的方法先得到错误字符串的长度。
size_t length = regerror (errcode, compiled, NULL, 0);
返回值:返回错误信息字符串的长度
#include<stdio.h>
#include <sys/types.h>
#include <regex.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argv,char *argc[])
{
if(argv < 2)
{
perror("argv");
exit(0);
}
const char *regular= argc[1];
const char *string= argc[2];
regex_t preg;
int comp_code = regcomp(&preg,regular,REG_EXTENDED) ;
if(comp_code != 0)
{
perror("regcomp");
exit(0);
}
regmatch_t pmatch[1];
int exec_code = regexec(&preg,string,1,pmatch,0);//数组长度为1
if(exec_code == 0)
{
// printf("%s match %s\n",string,regular);
int i = 0;
for(i = pmatch[0].rm_so;i < pmatch[0].rm_eo; i ++)
{
printf("%c",*(string + i));
}
printf("\n");
regfree(&preg);
return 0;
}
char buff[256] = {0};
size_t err_len = (comp_code,preg,buff,256);
err_len = err_len < sizeof(err_len) ? err_len:sizeof(err_len -1);
buff[err_len+1] = '\0';
printf("%s \n",buff);
regfree(&preg);
return 0;
}