shell是一个用c语言编写的程序,它是用户使用linux的桥梁。shell即是一种命令语言,又是一种此程序设计语言。
shell是一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统的内核服务。
shell脚本是一种为shell编写的脚本程序。业界所说的shell通常是指shell脚本。
1.语法的基本介绍
#!/bin/bash ####使用前面的#!来告诉系统它后面的参数是用来执行该文件的程序;
shell脚本是以.sh 结尾的的文件;
脚本的执行分为两种:a. sh 脚本的绝对路径 #####调用脚本,这个不需要文件含有执行权限;
脚本调试:sh -x /mnt/date.sh
b. chmod +x filename #####当我们的脚本写完,脚本需要执行权限
脚本的绝对路径 ######执行脚本,这个需要脚本含有执行权限;
2.注释
我们在编写shell编程时,以#开头的句子表示注释,除了上面提到的#!比较特殊,注释主要作用解释该命令及其工作原理;
多行注释:
:<<EOF
注释内容
EOF
多行注释还有其他格式:
3.shell字符串中的单引号和双引号:
单引号里的任何字符都会原样输出,单引号里面的变量是无效的;
单引号里面不能出现一个单独的单引号,转译过后的单引号也不行,可以成对出现;
而双引号可以出现变量和转译字符;
4.获取字符串的长度:
[root@localhost ~]# vi test.sh
a="thisnumber"
echo ${#a}
结果:
[root@localhost ~]# sh test.sh
10
提取字符串长度:#字符串第二个字符开始的五个字符
[root@localhost ~]# vi test.sh
#!/bin/bash
a="thisnumber"
echo ${a:1:5}
[root@localhost ~]# sh test.sh
hisnu
查找字符串:查找的字符串那个字符先出现就计算那个
[root@localhost ~]# vi test.sh
#!/bin/bash
a="thisnumber"
echo `expr index "$a" is`
[root@localhost ~]# sh test.sh
3
5.数组
在shell中,括号用来表示数组,数组元素使用“空格”符号分隔开;形式如下:
数组名={值1 值2 值3...} 或者
数组名={
值1
值2
值3
} 或者单独定义
数组名[0]=值1
数组名[1] =值2
读取数组:
${数组名[下标]} #下标数字是从0开始,对应数组里面的值1
${数组名[@]} #@符号获取数组里面所有的元素
也可以将获取的元素赋值给变量;
获取数组的长度:
获取数组的程度和获取字符串长度方法相同:
length = ${#数组名[@]}
也可可以获取单个元素长度:
length =${#数组名[n]}
6.编写脚本的时候我们还需要在脚本里面写入基本作用还有作者的一些信息,如下图:
每次写一个脚本,还要编辑以上信息比较繁琐,我们可以配置文件/etc/vimrc 里面直接写好利用快捷键直接显示;
注意:在67行里面设置快捷键的时候需要尝试,因为有些快捷键是由其他功能的,两者最好不要冲突;
66行命令的意思是新建的以 .sh 结尾的文件自动添加函数WESTOS;
7.脚本基本命令:
shell的输出命令printf
[root@localhost ~]# cat test.sh
printf "%-8s %-8s %-8s\n" name sex weight
printf "%-10s %-8s %-4.2f\n" one boy 50.67
printf "%-10s %-8s %-4.2f\n" tow boy 66.50
printf "%-10s %-8s %-4.2f\n" three girl 50.54
[root@localhost ~]# sh test.sh
name sex weight
one boy 50.67
tow boy 66.50
three girl 50.54
%s,%c,%d都是格式替换符:
d: Decimal 十进制整数 -- 对应位置参数必须是十进制整数,否则报错!
s: String 字符串 -- 对应位置参数必须是字符串或者字符型,否则报错!
c: Char 字符 -- 对应位置参数必须是字符串或者字符型,否则报错!
f: Float 浮点 -- 对应位置参数必须是数字型,否则报错!
%-10s表示一个宽度为10个字符的,(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中.2指保留2位小数
shell文件比较命令diff
1c1
< 12345 ######表示第一个文件的内容;
---
> 123 #######表示第二个文件的内容;
diff的补丁作用
将文件file和文件file1的不同生成补丁名命为diff.path;
需要给文件打补丁,将旧文件有缺失的变成全新文件没有缺失;需要使用补丁软件path.x86_64
补全文件file1, -b ###不全文件同时保存原文件;
查看文件;file1.orig是生成的原文件;
cut ###截取文件字符
-d ####指定分隔符
-f #####指定截取的第几列
-c #####指定截取的每列第几个字符
例如我们要展示系统用户;
sort 用于字符排序
-n ####纯数字排序 -r ####倒序
-u #####删除重复数字 -o ####将排序结果输出到指定文件
-t ####指定分隔符 -k ####指定要排序的列
uniq 对重复字符处理,常常与sort联合使用
-u ###显示唯一的一行
-d ###显示重复的行
-c ###显示出现的次数(前面数字是次数,后面数字是出现的数字)
&& 和 | |
&& 表示条件满足执行后面跟的命令
| | 表示条件不满足执行后面跟的命令
[ -e linux ] && echo yes | | echo no
####如果linux 文件存在这个条件满足则输出yes否则输出no;
shell命令:test 判断命令
test 命令和 [ ] 命令等同;
字符串的判定
test "$A"=="$B" | 等同于 [ "$A"=="$B" ] |
[ "$a" = "$b" ] | a是否于一致,不仅只是数值的相等· |
[“$a” != "$b" ] | a是否于b不相等 |
[ ! "$a" = "$b" ] | a于b不一致,且该条件不成立; |
-n | 字符串的长度不为零 |
-z | 字符串的长度为零 |
数值的判定
- eq | 等于 |
- le | 小于等于 |
- ne | 不等于 |
- ge | 大于等于 |
- lt | 小于 |
- gt | 大于 |
文件判定
格式:[ 参数 filename ]
-e | 文件是否存在 |
-f | 是否为一般文件 |
-r | 文件是否可读 |
-w | 文件是否可写 |
-x | 文件是否可执行 |
-L | 是否为链接 |
-S | 文件是否为套接字 |
-b | 文件是否为块设备 |
-d | 文件是否为目录 |
-c | 文件是否为字符 |
两个文件之间的比较
test file1 -nt file2 #判断文件1是否比文件2新(nt: new than)
test file1 -ot file2 #判断文件1是否比文件2旧(ot: old than)
逻辑运算符
非( !) ####对表达式取反;
或( -o 或者| | ) ####两个表达式任何一个为真;
与( -a 或者&&) ####两个表达式都为真;
( ) ####用于改变表达式的优先级
这三个逻辑操作符用于多条件链接;优先级为 ”!“>"-a">"-o"
tr 改变字符的大小写
tr是translate的简写,主要用于压缩重复字符,删除文件中的控制字符以及进行字符转换操作。
参数
-s 压缩重复字符
cat file | tr -s [ "\n" ] ####过滤空行显示文件内容
-d ####删除字符
删除显示的小写字符;或者删除大小写字母;
-t ####字符替换
-c ####字符补集替换
echo agsgdyguDHDEWFUYUE > linux ####将大小写字母导入文件linux
tr 'a-z' 'A-Z' < linux ####将Linux文件里面的小写字母用大写字母取代并打印出来;
注意 : 括号的方向,一旦方向错误,文件里面的内容会被丢失;
find 查询
-type ####按照类型查找
-user ####按照属主查找
-group ###按照属组查找
-a ###并且,通常表示至少两个条件都满足
-perm ####按照权限条件查找
注意:/444 /表示或的意思;查找u位有w权限或者g位有w权限或者o位有w权限
-444 -表示且的意思;查找u位g位o位都有w权限的
-644 ###查找u位含有r权限和w权限,且g位含有r权限,且o位含有r权限;
/644 ###查找u位含有r权限或者w权限,或者g位含有r权限,或者o位含有r权限;
-size ###按照文件大小查找
find /mnt/ -size -20M ####查找小于20M
find /mnt/ -size +20M ####查找大于20M
-maxdepth ###按照最大深度查找(默认最大深度为2层)
-mindepth ###按照最小深度查找
改变软连接的属组只能改变软连接的指向文件的属组;
grep 过滤
文本过滤命令:greps是文本搜索工具,根据用户指定的模式对目标文件进行匹配检查,打印匹配到的行;
grep:由正则表达式或者字符以及基本文本文字所编写的过滤条件;
-E ####扩展正则表达式
grep 关键字 文件 ####过滤含有关键字的行
grep root passwd ###模糊过滤root字符
grep -E "\<root" passwd ####模糊过滤以root开头的字符
grep -E "\<root\>" passwd ####精确过滤以root字符
grep -E -i "^\<root\>" passwd ###忽略大小写过滤以root字符开头的行;
grep -E -i "root|ROOT" passwd ###模糊过滤root和ROOT字符;
grep ^root 文件 ####过滤以root开头的行
grep root$ 文件 ###过滤以root结尾的行
grep -o 关键字 文件 ####将过滤的关键字竖列打印出来
grep -i 关键字 文件 ####忽略大小写
grep -E "root\>" 文件 ####以root结尾的
grep -E "\<root" 文件 ####以root开头的
grep匹配字符出现次数
* 匹配字符出现[0-任意词]
? 字符出现0-1次
+ 字符出现1-任意次
{ n } 字符出现n次
{ n , m } 字符出现至少n次,最多m次
{ 0 , m } 字符出现0-m次
{ n , 0 } 字符出现至少m次
(xy)n 字符出现n 次
sed (sream editor) 行编辑器 对字符的处理
sed 符合模式条件的处理 不符合条件模式的不予处理
处理完成以后把缓冲区的内容送往屏幕;接着处理下一行,直至文件的末尾
-p 显示
-d 删除
-a 添加
-c 改变
-w 写入
-i 插入
p 模式编辑
sed -n '/^UUID/p' filename ###显示UUID开头的行
sed -n '/UUID$/p' filename ###显示UUID结尾的
sed -n '2,6p' filename ###显示第2行和第6行
sed -n '2,6!p' filename ###显示除了第2行和第6行
a 模式编辑
sed '/^UUID/a \hello sed /etc/fstab' ###在文件fstab里面以UUID开头行后面添加hello sed
sed '/^UUID/a \hello sed\westos /etc/fstab' ###在hello sed 后面添加westos
awk 报告生成器
awk处理机制:awk会逐行处理文本
awk -F : 'BEGIN{print "NAME"}{print $1}' passwd
##passwd文件里面以: 为分隔符,开始给第一行显示NAME且打印第一行;
awk -F : '/bash$/{print $1}' passwd ###显示passwd文件以bash结尾的行,并且打印第一竖列;
注意不要忘记-F 否则不识别:将一行当作一个列:
awk -F '/^root/{print $1}' passwd ###显示passwd文件以root开头的行,并且打印第一列;
awk -F '/bash$/{print $1}END{print NR}' passwd##显示passwd文件以bash结尾的行,并且打印第一列;统计行数;
awk -F : 'NR==3{print $1}' passwd ####显示第三行第一列;
awk -F : 'NR>=3&&NR<=6{print $1}' passwd ###显示第三行和第六行的第一列;
awk -F : 'NR>=3&&NR<=5&&/^a | nologin$/{print $1,$7}' passwd
###显示第3行到第5行,并且以a开头或者以nologin结尾,打印第一竖列与第七竖列;
变量
在shell编程中,变量必须遵守几点规则:
1.命名时只能使用英文字母,数字和下划线,首个字母不能以数字开头。
2.中间不能含有空格,可以使用下划线。
3.不能使用标点符号;
4.不能使用bash里面的关键字;
要赋值给一个变量:a="hello world",现在打印变量a的内容:echo "A is : " echo $a;有时候变量名也容易和其他文字混淆:num=2 ,打印出来 :echo "this is the $numnd" ;输出结果this is the ,不会是我们想的结果: this is the 2nd ;因为shell回去搜索变量numnd 的值,因为是空值。我们可以使用花括号来定义: echo "this is the ${num}nd";
语句给变量赋值:
for file in `ls /etc` 或者 for file in ${ls /etc}
只读变量:使用readonly命令来定义变量为只读变量,只读变量不能被改变;
readonly 变量
删除变量:unset 命令可以删除变量。
unset 变量
linux shell 的变量分类:三种分别为内部变量,环境变量,用户变量。
内部变量:系统提供,不用定义,不能修改;
环境变量:系统提供,不用定义,可以修改,利用export将用户变量转为环境变量;
用户变量:用户定义,可以修改;
(1)内部变量(系统变量,环境变量,参数变量,预定义变量)
内部变量是Linux所提供的一种特殊类型的变量,这类变量在程序中用来作出判断。在shell程序内这类变量的值是不能修改的。
表示方法 | 描述 |
$n | $0表示执行的脚本名$1 表示第一个参数,$2 表示第二个参数 ... |
$# | 命令行参数的个数 |
$0 | 当前程序的名称 |
$? | 前一个命令或函数的返回码 |
$* | 以"参数1 参数2 ... " 形式保存所有参数 |
$@ | 以"参数1" "参数2" ... 形式保存所有参数 |
$$ | 本程序的(进程ID号)PID |
[root@localhost ~]# vi test.sh
echo "$0" #执行的脚本名
echo "$1" #传递的第一个参数
echo "$#" #传递的参数个数
echo "$*" #传递的参数作为一个字符串显示
[root@localhost ~]# sh test.sh 1 2 3
test.sh
1
3
1 2 3
如何检查上条命令执行结果返回状态?0代表成功,其他表示失败
在shell脚本里面判断如下:
id httpd > /dev/null
if [ $? -eq 0 ];then
echo "user httpd is exit!"
else
groupadd httpd
useradd -g httpd -M -s /sbin/nologin httpd
fi
或者
id httpd && echo "user httpd is exit" || groupadd httpd && useradd -g httpd -M -s /sbin/nologin httpd
(2) 环境变量
Linux环境(也称为shell环境)由许多变量及这些变量的值组成,由这些变量和变量的值决定环境外观。这些变量就是环境变量。
包括两部分:一是,由系统设置的,主要包括: HOME,LOGNAME,MAIL,PATH,PS1,PWD,SHELL,TERM
二是,用户在命令行中设置的,使用export命令,但是用户注销时值将丢失
(3)用户变量(私有变量,本地变量)
在命令行中自己设定的.
设置当前shell的变量
我们赋予当前shell一个变量a=1,可以查看当前变量值为1,我们在打开一个当前shell的子shell,查看变量a的值为空;
export a=1 ####将变量设定为当前shell以及子shell的环境变量
我们在打开一个子shell ,可以查看变量生效;
设置用户shell变量
在root用户的家目录下,我们卡伊看见有个隐藏文件.bash_profile 进行编辑添加 export a=2
###当前用户环境变量设置完成,
退出当前用户在进入改变量也生效;
设置系统变量
1.我们赋予当前shell 变量a=1,切换其他用户不生效;
2.以root用户的身份在/etc/profile文件里面添加 export a=1
需要注意的是:我们在配置文件系统变量设置完成,不能立刻生效,需要进行读取文件更新环境菜可以生效;
source /etc/profile ####读取配置文件,更新环境
字符的转译以及变量的声明
\ | 转译单个字符; |
" " | 弱引用。批量转译”“中出现的字符; |
' ' | 强引用,批量转译' ' 中出现的字符; ' ' 与" "两者区别在于," " 不能转译\ ` ! $ |
${ } | 变量声明 |
shell命令:read 提示用户输入,并将输入赋值给变量
read命令从标准输入中读取一行,并把输入行的每一个字段的值指定给shell变量
p ”提示语“ ##提示语句;屏幕会显示提示语
read后面的变量可以只有一个,也可以有多个;如果输入很多个数据时,将第一个数据给第一个变量,将第二个数据给第二个变量,后面过多的数据则集中给最后一个变量;
-n number ###命令计数;当输入的字符数达到设定的字符数时,执行结果自己执行不用回车,并将输入的数据赋值给变量;
-t number ###等待时间;相当于计时器,当一个命令在规定时间没有得到反应时,read命令返回一个非零退出状态,放置命令一直等待客户的输入;
-s ###关闭回显;使得read命令输入的数据不出现在屏幕上(实际上数据是显示的,只是read命令将文本颜色设置成与背景颜色相同的颜色)
1.示例:vim read.sh ####编写一个read.sh脚本
我们调用脚本进行查看;
如果我们不想让别人知道我们输入什么密码或者用户名,在脚本后面添加-s
alias ###定义别名
1.暂时定义别名
测试结果:
这样的方法只是暂时的,当我们退出当前用户在进入的话,改别名会失效;
unalias ####删除设置里面的xie别名;
2.永久进行别名设置
编辑配置文件/etc/bashrc, 配置完成需要进行读取更新,source /etc/bashrc
如不需要该别名,删除配置文件里面的命令或者注释掉,使用unalias删除设置的命令
Hostname=${hostname} Hostname=`hostname`
$? 是命令在执行完成之后产生的退出值,范围是0-255;当$0=0时表示标示命令执行没有错误输出,这个值可以用exit命令执行;
测试:
执行命令错误返回的执行状态报告;
执行命令正确;
错误55退出
shell流程控制
sh的流程控制不能为空;
if语句:
格式一:
if condition
then
command1
...
fi
格式二:
if condition
then
command1
...
else
command
fi
格式三:
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
或者:
if [${ps -ef | grep -c "ssh"} -gt 1]; then echo "true"; fi
for 循环语句
for var in itemN
do
command1
...
done
或者
for var in itemN;do command1 ...;done
while 语句
while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件
while condition
do
command
done
无限循环
while :
do
command
done
或者
while true
do
command
done
或者
for (( ; ; ))
until 循环:
until 循环执行一系列命令直至条件为 true 时停止;until 循环与 while 循环在处理方式上刚好相反;一般 while 循环优于 until 循环
until condition
do
command
done
case 语句
Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
*) #表示捕获其他不在范围的值;
command1
command2
...
commandN
;;
esac
取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
跳出循环的命令:
break 命令:break命令允许跳出所有循环(终止执行后面的所有循环
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done
continue 命令:它不会跳出所有循环,仅仅跳出当前循环
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字: "
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的!"
continue
echo "游戏结束"
;;
esac
done