IP地址配置
1.setup工具
vi /etc/sysconfig/network-scripts/ifcfg-eth0
ONBOOT=yes
service network restart
2.修改虚拟机连接方式为桥接
3.编辑—虚拟网络编辑器—vmnet0--桥接到有线网卡
4.UUID错误(针对复制镜像生效)
vi/etc/sysconfig/network-scripts/ifcfg-eth0 删除MAC地址行
rm –rf/etc/udev/rules.d/70-persistent-net.rules 删除网卡和MAC地址绑定文件
重启系统
软件包安装
软件包分类:源码包、二进制包(脚本安装包)
源码包的编译:
vimhello.c
#include <stdio.h>
intmain (void)
{
printf (“hello world\n”);
}
rpm–ivh /mnt/cdrom/Packages/gcc-4.4.6-4.el6.i686.rpm
gcc–c hello.c
gcc–o hello hello.o
./hello #执行hello文件
源码包的优点:
开源,如果有足够的能力,可以修改源代码
可以自由选择所需的功能
软件是编译安装 ,所以更加适合自己的系统,更加稳定也效率更高
卸载方便
源码包的缺点:
安装过程步骤较多,尤其是安装较大的软件集合时,容易出现拼写错误
编译过程时间较长,安装比二进制安装时间长
因为是编译安装,安装过程中一旦报错新手很难解决
二进制包分类:DPKG包(Debian开发),RPM包(Red Hat开发)
RPM包优点:
包管理系统简单,只通过几个命令就可以实现包的安装、升级、查询和卸载
安装速度比源码包安装快的多
RPM包的缺点:
经过编译,不再可以看到源代码
功能选择不如源代码灵活
依赖性。
RPM包的依赖性:树形依赖、环形依赖(同时安装)、模块依赖(www.rpmfind.net)
关于源码包和二进制包的选择:一般要求稳定的,给客户用的访问量大的服务安装用源码包;给系统自己本身使用的,邮件之类的服务安装用二进制包。
rpm包的命名:httpd-2.2.15-15.el6.centos.1.i686.rpm
httpd 软件包名
2.2.15 软件版本
15 软件发布的次数
el6 软件发行商
i686 适合的硬件平台(x86_64只适合64位CPU安装,noarch没有硬件限制)
rpm rpm包的扩展名
RPM包的默认安装位置
/etc/ 配置文件安装目录
/usr/bin/ 可执行的命令安装目录
/usr/lib/ 程序所使用的函数库保存位置
/usr/share/doc/ 基本的软件使用手册保存位置
/usr/share/man/ 帮助文档保存位置
包全名:操作未安装的rpm包
包名:操作已安装的rpm包
rpm –ivh 包全名(注意路径)
-i install安装
-v 显示更详细信息(verbose)
-h 显示安装进度(hash)
--nodeps 不检测依赖性安装
--replacefiles 替换文件安装,某个文件已经存在
--replacepkgs 替换软件包安装,软件包已经安装
--force 强制安装,为--replacefiles和--replacepkgs的综合
--test 测试安装,不会实际安装,只检测依赖性
--prefix 指定安装路径,rpm包一般采用默认路径
服务启动:service 服务名 start/stop/restart/status
/etc/rc.d/init.d/服务名 start
rpm –Uvh 包全名 #升级安装(upgrade)
rpm –Fvh 包全名 #升级安装,未安装过,则不安装(freshen)
rpm –e 包名 #卸载
rpm –q 包名 #查询包是否安装
rpm –qa | grep httpd #显示所有安装包
rpm –qi 包名 #查询包的信息
rpm –qip 包全名 #查询没有安装的包的信息
rpm –ql 包名 #查询包中文件的安装位置
rpm –qf 系统文件名 #查询系统文件属于哪个包
rpm –qR 包名 #查询软件包所依赖的软件包
rpm –qRp 包全名 #查询没有安装的包的依赖性
rpm –V 包名 #校验安装的某个包是否被修改
rpm –Va #校验本机已经安装的所有软件包
rpm –Vf 系统文件名 #校验某个系统文件是否被修改
S #文件大小是否改变
M #文件的类型或权限是否被改变
5 #文件MD5校验和是否改变(可看成文件内容)
D #设备的主从代码是否改变
L #文件路径是否改变
U #文件的所有者是否改变
G #文件的所属组是否改变
T #文件的修改时间是否改变
c #配置文件(config file)
d #普通文件(documentation)
g #鬼文件(ghost file)
l #授权文件(licensefile)
r #描述文件(read me)
数字证书,为原厂公钥文件
/mnt/cdrom/RPM-GPG-KEY-CentOS-6 #光盘中数字证书位置
/etc/pki/rpm-gpg/ RPM-GPG-KEY-CentOS-6 #系统中数字证书位置
rpm --import /etc/pki/rpm-gpg/ RPM-GPG-KEY-CentOS-6 #导入数字证书
rpm –qa | grep gpg-pubkey #查询已安装的证书
备份:find 备份目录或文件–print | cpio –ocvB >指定目录生成.cpio文件
-o #copy-out模式,备份
-v #显示过程
-c #使用较新的portable format存储方式
-B #设定输出块为5120bytes,而不是模式的512butes
还原:cpio –idvcu <指定目录生成的.cpio文件
-i #copy-in模式,还原
-d #还原时自动新建目录
-u #自动使用较新的文件覆盖较旧的文件
备份时使用绝对路径,恢复的数据会直接回到原来的绝对路径;备份时使用相对路径,数据会恢复到当前路径。
复制模式:find 备份目录或文件–print | cpio –p 指定目录
提取RPM包中文件:rpm2cpio 包全名 | cpio –idv . 文件绝对路径
rpm2cpio #将rpm包转换为cpio格式的命令
.是一种格式,不能省略
dir与ls有相同的作用。
搭建光盘yum源
cd/etc/yum.repos.d/
mvCentOS-Base.repo CentOS-Base.repo.bak
mount/dev/sr0 /mnt/cdrom
vi/etc/yum.repos.d/CentOS-Media.repo
baseurl=file:///mnt/cdrom/ #指定yum源位置
enabled=1 #yum源文件生效
[base] #容器名称,一定要放在[]中
name #容器说明,可以自己随便写
mirrorlist #镜像站点,这个可以注释掉
baseurl #yum源服务地址
enabled #此容器是否生效,enable=1为生效,enable=0为不生效
gpgcheck #RPM的数字证书是否生效
gpgkey #数字证书的公钥文件保存位置
yum –y install 包名 #安装
yum –y remove 包名 #卸载(不建议用)
yum –y update 包名 #升级
yum list #查询所有可以安装的包
yum list 包名 #查询yum源服务器中是否包含某个软件包
yum search 关键字 #搜索yum源服务器上所有和关键字相关的包
yum info 包名 #查询指定软件包的信息
yum组管理命令
yumgrouplist #列出所有可用的软件组列表
yumgroupinfo 软件组名 #列出软件组中包含的软件
yumgroupinstall软件组名 #安装指定软件组
yumgroupremove 软件组名 #卸载指定软件组
源码包安装
解压
cd 解压目录
查看安装文档 INSTALL README
编译前准备 ./configure--prefix /usr/local/目录名
检测系统环境,定义功能选项。把检测结果和定义的选项写入Makefile
编译make(出错后makeclean)
编译安装make install
启动 /usr/local/目录名
源码包可以链接到service下,不建议用
删除:直接删除安装目录
RPM包一般为系统自带,源码包在官网下载
给客户端,公网访问的服务不建议改端口。ssh可以改端口。
echo $LANG 查看语言支持
LANG=en_US 临时修改语言支持
diff 选项 old new > *.patch #生成补丁
-a 将任何文档当做文本文档处理
-b 忽略空格造成的不同
-B 忽略空白行造成的不同
-I 忽略大小写造成的不同
-N 当比较两个目录时,如果某个文件只在一个目录中,则在另一个目录中视作空文件
-r 当比较目录时,递归比较子目录
-u 使用统一的输出格式
patch –pn < 补丁文件 #打入补丁
n为数字,若生成补丁用相对路径,n为0;若生成补丁用绝对路径,n为文件夹距离
脚本安装程序 ./setup.sh #要确保perl已经安装
安装脚本执行时注意:SSL不要启用
函数库分类
静态函数库:直接整合在程序中,以“*.a”结尾
动态函数库:需调用,以“*.so”结尾
ldd –v 可执行文件名 #安装函数库
ldd 可执行文件名(/bin/ls) #查看调用的函数库
cp *.so /usr/lib/ #把函数库拷贝入/usr/lib目录(函数库没正常安装时才需手工操作)
vi /etc/ld.so.conf #修改函数库配置文件
ldconfig #从/etc/ld.so.conf中把函数库读入缓存
ldconfig –p #列出系统缓存中所有识别的函数库
du -sh 目录名 #统计目录大小
用户和用户组管理
/etc/passwd 用户信息文件
root:x:0:0:root:/root:/bin/bash
用户名:密码标识:UID:GID:用户说明:用户家目录:登录shell
密码标识x代表有密码,用户正常。若用户没有密码只能本地登录。
UID为0是超级用户,1-499为系统用户(伪用户),500-65535为普通用户。
普通用户变成超级用户只需把用户UID改为0
登录shell为/bin/bsah,/sbin/nologin为不能登录伪用户。
数据库用户与系统用户完全不同。
/etc/shadow 影子文件
root:68cducdbofehrwq:15575:0:99999:7:::
用户名:加密密码:密码最近更改时间:两次密码修改的间隔时间:密码有效期:密码修改到期前的警告天数:密码过期后的宽限天数:密码失效时间:保留
密码由MD5(128位加密)变为SHA512加密,在加密密码前加入“!”或“*”可以让密码值暂时失效,达到暂时禁止用户登录的效果。所有伪用户的密码都是“!!”或“*”。
密码最近更改时间为时间戳,以1970年1月1日为标准时间。时间戳为0,第一次登录必须修改密码。
时间戳转日期:date –d “1970-01-01 16659 days”
日期转时间戳:echo $(($(date --date=”2015/08/12” +%s)/86400+1))
两次密码的修改间隔时间和密码有效期是与密码最近更改时间相比。
密码有效期为0,不能登录
密码修改到期前的警告天数和密码过期后的宽限天数是和密码有效期相比。
密码失效时间同样要写成时间戳。如果超过了失效时间,即使密码没有过期,用户也不能登录。时间为0,不能登录。
/etc/group 组信息文件
root:x:0:root
组名:组密码位:GID:附加组是此组的用户
初始组:每个用户初始组只能有一个,一般是和用户名相同的组作为初始组。
附加组:每个用户可以属于多个附加组。
/etc/gshadow
用户组设定了组管理员和组密码,组密码保存在这个文件中。
用户的家目录,root为/root,普通用户一般为/home/用户名
用户邮箱目录在/var/spool/mail中
用户模板目录/etc/skel/,新建用户包含的初始文件所在位置。
手工删除用户需修改6个文件
/etc/passwd,/etc/shadow,/etc/group,/etc/gshadow,/home/user1,/var/spool/mail/user1
useradd 选项 用户名 #添加用户
-u数字 指定UID
-g组名 指定初始组,一般不要指定
-G组名 指定附加组
-c组名 添加说明
-d目录 手工指定家目录,不需事先建立
-sshell /bin/bash
useradd添加用户时参考的默认值文件为/etc/default/useradd和/etc/login.defs
/etc/default/useradd
GROUP=100 建立用户的默认组,目前采用私有用户组机制
HOME=/home 用户的家目录默认位置
INACTIVE=-1 密码过期后的宽限天数,-1代表永不失效
EXPIRE= 密码失效时间,默认永久有效
SHELL=/bin/bash 用户的默认shell
SKEL=/etc/skel 定义用户模板目录位置
CREATE_MALL_SPOOL=yes 默认给新建用户创建邮箱
/etc/login.defs
MAIL_DIR /var/spool/mail 新建用户的默认邮箱位置
PASS_MAX_DAYS 99999 密码的有效期
PASS_MIN_DAYS 0 两次密码的修改间隔时间
PASS_MIN_LEN 5 密码的最小长度,登录验证已被PAM模块取代
PASS_WARN_AGE 7 密码到期前的警告天数
UID_MIN 500/UID_MAX 60000 用户的UID范围
GID_MIN500/GID_MAX 60000 用户的GID范围
CREATE_HOME yes 建立用户自动建立家目录
UMASK 077 用户家目录的默认权限为700
USERGROUPS_ENAB yes userdel删除用户时默认删除初始组
ENCRYPT_METHOD SHA512 用户密码使用SHA512散列模式加密
usermod –u –G –c –d –s 用户名 #修改用户信息
-L 锁定用户
-U 解锁
-l新名 旧名 用户改名
usermod –G 组名 用户名 #把用户加入组
userdel –r 用户名 #连带家目录一起删除用户
passwd 选项 用户名 #设定用户密码
passwd不跟用户名为修改当前用户密码
-S 查询用户密码的密码状态
-l 锁定用户密码,用户不允许登录
-u 解锁
--stdin 允许管道符输入密码 echo “1234”| passwd --stdin user2
groupadd 组名 #添加组
groupdel 组名 #删除组(没有用户的初始组为此组)
gpasswd –a 用户名 组名 #把用户加入组
gpasswd –d 用户名 组名 #把用户从组中删除
chage –d 0 用户名 #一登录就需修改用户密码
id 用户名 #显示用户的UID,初始组,附加组
su – 用户名 #连带环境变量一起切换用户身份
env #查看环境变量
newgrp 组名 #修改所有者创建文件的有效组(所属组)
selinux可以限制root的权限
df –h #查看系统分区
dumpe2fs –h /dev/sda3 #查询指定分区详细文件系统信息
-h 仅显示超级块中信息,而不显示磁盘块组的详细信息
mount –o remount, acl / #重新挂载根分区,并加入ACL权限,手工开启分区的ACL权限
vi /etc/fstab #永久开启ACL权限,需修改配置文件
mount –o remount / #重新挂载文件系统或重启系统,使修改生效
getfacl 文件名 #查询文件的ACL权限
setfacl –m u:用户名:权限 文件名 #设定ACL权限
setfacl –m d:u: 用户名:权限 文件名 #设定ACL默认权限,只能是目录
如果给目录赋予ACL权限,以上两条命令都要输入
setfacl –x u:用户名 文件名 #删除指定ACL权限
setfacl –b 文件名 #删除所有ACL权限
setfacl –k 文件名 #删除默认ACL权限
setfacl –m g:组名:权限 –R 文件名 #递归设定
setfacl –m m:rwx 文件名 #设定最大有效权限mask
sudo授权,给普通用户赋予部分管理员权限(如重启服务器等)
/sbin/, /usr/sbin/目录下命令只有超级用户才能使用。
root/%wheel ALL=(ALL) ALL
用户名/组名 被管理主机的地址=(可使用的身份) 授权命令(绝对路径)
用户名/组名:代表root给哪个用户或用户组赋予命令,注意组名前加“%”
用户可以用指定的命令管理指定IP地址的服务器。如果写ALL,代表可以管理任何主机,如果写固定IP,代表用户可以管理指定的服务器。如果是一台独立的服务器,这里写ALL和服务器的IP地址,作用是一样的。而写入网段,只有对NIS服务这样用户和密码集中管理的服务器才有意义。如果写本机的IP地址,不代表只允许本机的用户使用指定命令,而代表指定的用户可以从任何IP地址来管理当前服务器。
可使用身份:就是把来源用户切换成什么身份使用,(ALL)代表可以切换成任意身份,这个字段可以省略。
授权命令:代表root把什么命令授权给普通用户,需要给哪个命令授权,写入命令名即可,一定要写成绝对路径。
visudo #修改配置文件进行授权
sudo –l #查看可用的授权
aa ALL=/usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd“ ”, !/usr/bin/passwd root
#赋予aa改密码权限,取消对root的密码修改(授权aa新建用户)
SetUID的含义:
只有可以执行的二进制程序才能设定SUID权限;
命令执行者要对该程序拥有x(执行)权限;
命令执行者在执行该程序时获得该程序文件属主的身份;
SUID权限只在该程序执行过程中有效,也就是说身份改变只在程序执行过程中有效。
SUID是系统为解决某些普通用户权限不足的问题,如果取消SUID权限,普通用户就不能修改自己的密码了。
SUID比较危险,应注意:
关键目录应严格控制写权限,比如“/”“usr”等;
用户的密码设置要严格遵守密码三原则;
对系统中默认应该具有SUID权限的文件作一列表,定时检查有没有之外的文件被设置SUID权限。
检测SUID的脚本
#!/bin/bash
find/ -perm -4000 –o –perm -2000 > /tmp/setuid.check
#搜索系统中所有拥有SUID和SGID的文件,并保存到临时目录中
fori in $(cat /tmp/setuid.check)
#做循环,每次循环取出临时文件中的文件名
do
grep$i /root/suid.list > /dev/null
#比对这个文件名是否在模板文件中
if[“$?” !=”0”]
#如果在,不报错
then
echo“$i isn’t in listfile!” >> /root/suid_log_$(date+%F)
#如果文件名不在模板文件中,则报错,并把报错报错到日志中
fi
done
rm –rf /tmp/setuid.check
SetGID即可以针对文件生效,也可以针对目录生效。
SGID针对文件含义;
只有可执行的二进制程序才能设置SGID权限
命令执行者要对该程序拥有x(执行)权限
命令执行者在执行程序的时候,组身份升级为该程序文件的属组
SGID权限同样只在该程序执行过程中有效,也就是说组身份改变只在程序执行过程中有效。
SGID针对目录的含义:
普通用户必须对此目录拥有r和x权限,才能进入此目录
普通用户在此目录中的有效组会变成此目录的属组
若普通用户对此目录拥有w权限时,新建的文件的默认属组是这个目录的属组
Sticky BIT黏着位,简称SBIT,仅对目录有效。
普通用户对该目录拥有w和x权限;
如果没有黏着位,因为普通用户拥有写权限,所以可以删除此目录下所有文件,包括其他用户建立的文件。一旦赋予了黏着位,除了root可以删除所有文件,普通用户就算拥有写权限,也只能删除自己建立的文件,不能删除其他用户建立的文件。
特殊权限的表示方法:
SUID 4 u+s
SGID 2 g+s
SBIT 1 o+t
chattr [+-=] [选项] 文件或目录名 #修改文件系统属性权限
+:增加权限 -:删除权限 =:等于某权限
i:如果对文件设置i属性,那么不允许对文件进行删除、改名,也不能添加和修改数据;如果对目录设置i属性,那么只能修改目录下文件的数据,但不允许建立和删除文件。
a:如果对文件设置a属性,那么只能在文件中增加数据,但是不能删除也不能修改数据;如果对目录设置a属性,那么只允许在目录中建立和修改文件,但是不允许删除。
e:linux中绝大多数的文件都默认拥有e属性,表示该文件是使用ext文件系统进行存储的,而且不能使用“chattr –e”命令取消e属性。
lsattr 选项 文件名 #查看文件系统属性权限
-a 显示所有文件和目录
-d 若目标是目录,仅列出目录本身的属性,而不是子文件的
文件系统管理
硬盘速度:500MB/s;CPU速度:2G(Hz)x8(64位)字节x8线程
硬盘是计算机发展的瓶颈
硬盘逻辑结构:扇区,磁道。
每个扇区的大小是固定的,为512byte,扇区也是磁盘的最小存储单位。
硬盘的大小=磁头数x柱面数x扇区数x每个扇区的大小
磁头数表示硬盘总共有几个磁头,也可以理解为硬盘的盘面x2;
柱面数表示硬盘每一面盘片有几条磁道;
扇区数表示每条磁道上有几个扇区。
硬盘接口:IDE,SCSI,SATA,SAS,PCI-E,PCI
对比项目 固态硬盘 机械硬盘
容量 较小 大
读写速度 极快 一般
写入次数 5000次-10万次 没有限制
工作噪音 极低 有
工作温度 极低 较高
防震 很好 怕震动
重量 低 高
价格 高 低
super block(超级块):记录整个文件系统的信息,包括block与inode的总量,已经使用的inode和block的数量,未使用的inode和block的数量,block与inode的大小,文件系统的挂载时间,最近一次的写入时间,最近一次的磁盘检验时间等。
date block(数据块):用来实际保存数据的,block的大小(1Kb、2Kb、4Kb)和数量在格式化后就已经决定,不能改变,除非重新格式化。每个block只能保存一个文件的数据,要是文件数据小于一个block块,那么这个block的剩余空间不能被其他文件占用;要是一个文件数据大于一个block块,则占用多个block块。Windows中磁盘碎片整理就是把一个文件占用的多个block块尽量整理到一起,这样可以加快读写速度。
inode(i节点):用来记录文件的权限,文件的所有者和属组,文件的大小,文件的状态修改时间,文件的最近一次读取时间,文件的最近一次修改时间,文件的数据真正保存的block编号。每个文件需要占用一个inode.
df –ahT
-a #显示特殊文件系统,这些文件系统几乎都是保存在内存中,占用量为0
-h #单位换算为习惯单位
-T #多出文件系统类型
du [选项] [目录或文件名]
-a #显示每个子文件的磁盘占用量,默认只统计子目录的磁盘占用量
-s 统计占用总量
-h
du与df的区别:du统计文件大小;df查看空间占用情况
lsof #查看文件
fsck –y /dev/sdb1 #自动修复文件系统
dumpe2fs /dev/sda1 #显示磁盘状态
Filesystemvolume name 卷标名
Lastmounted on 挂载点
FilesystemUUID UUID
Defaultmount options 挂载参数
Filesystemstate:clean 文件系统状态,正常
Inodecount inode总数
Blockcount 块总数
Blocksize 块大小
Inode inode的大小
stat 文件名 #查看文件的详细时间
I0Block 系统分区块大小
Links 硬链接数
modify 数据修改时间
change 状态修改时间
file 文件名 #判断文件类型
type 命令名 #判断命令类型
fdisk –l #查看系统所有硬盘及分区
必须激活一个主分区才能安装系统,默认激活第一个主分区。用“*”表示。
fdisk dev/sdb #进行磁盘分区(分区还没有分区号)
d 删除一个分区
l 显示已知的文件系统类型。82为linux swap分区,83为linux分区
m 显示帮助菜单
n 新建分区
p 显示分区列表
q 不保存退出
t 改变一个分区的系统ID
w 保存退出
a 设置可引导标记
b 编辑bsd磁盘标签
c 设置DOS操作系统兼容标记
o 建立DOS分区表
s 新建空白SUN磁盘标签
u 改变显示记录单位
v 验证分区表
x 附加功能
partprobe #强制重读所有分区文件,重新挂载分区文件内所有分区。分区没有被显示出来时可以用此命令,或者重启
mkfs –t ext4 /dev/sdb1 #格式化分区
mke2fs [选项] 分区设备文件名
-t文件系统:指定格式化成哪个文件系统
-b字节:指定block的大小
-i字节:指定“字节/inode”的比例,也就是多少个字节分配一个inode
-j:建立带有ext3日志功能的文件系统
-L卷标名:给文件系统设置卷标名,不用e2label设定了
vi /etc/fstab #修改分区自动挂载文件
/dev/sdb1 /disk1 ext4 defaults 1 2
设备文件名 挂载点 文件系统 挂载选项 是否可以被备份 是否检测磁盘fsck
备份:0不备份,1每天备份,2不定期备份
检测:0不检测,1启动时检测,2启动后检测
UUID为硬盘通用唯一识别码,可以用UUID进行挂载,而不用分区设备文件名挂载。
UUID的查询:dumpe2fs/dev/sdb5或ls –l /dev/disk/by-uuid/
mount –a #重新挂载所有内容,进行重启测试
/etc/fstab文件修复:可以进入系统,重新挂载读写权限(mount–o remount, rw /),修改配置文件,就可以正常启动。
MBR分区表:支持最大分区是2TB,最多支持4个主分区,或3个主分区1个扩展分区。
GPT分区表:支持最大18EB分区,最多支持128个分区,一个系统保留分区,127个用户自定义分区。
parted命令分区只能直接格式化成ext2文件系统。
parted /dev/sdb #进入parted交互模式
help 显示所有的命令帮助
print 显示分区表,活动设备,空闲空间,所有分区
mklabel ,mktable 创建新的磁盘卷标(分区表)
mkpart 创建一个分区
mkfs 在分区上建立文件系统
resize 修改分区大小
rm 删除分区
quit 退出
check 做一次简单的文件系统检测
cp 复制文件系统到另外一个分区
mkpartfs 创建分区,并建立文件系统
move 移动分区
name 给分区命名
rescue 修复丢失的分区
select 选择需要编辑的设备
set 改变分区标记
toggle 切换分区表的状态
unit 设置默认单位
version 显示版本
使用print可以查看分区表的信息,包括硬盘参数,硬盘大小,扇区大小,分区表类型和分区信息。分区信息共七列,分别是:
Number:分区号
Start: 分区起始位置,这里不再像fdisk用柱面表示,而是使用Byte更加直观
End: 分区结束位置
Size: 分区大小
Type: 分区类型
File system:文件系统类型,parted不能直接把分区格式化成ext4文件系统,但是可以识别
Flags: 分区的标记
修改了分区表,原有分区中的数据都会消失,而且需要重启系统才会生效。重启系统前要注意把/etc/fstab文件中的原有分区删除掉。
分区类型是标识主分区、扩展分区和逻辑分区的,这种标识只在MBR分区中使用,在GPT分区表中不再有Type类型。
如果要格式化ext4文件系统,可以退出parted交互命令,用mkfs,但格式化成ext4文件系统之后,就不能用parted命令调整大小了。
parted调整已经挂载使用的分区时,是不会影响分区中数据的,也就是说数据不会丢失。但是一定要先卸载分区,再调整分区大小,否则数据也是会出现问题的。要调整大小的分区必须已经建立了文件系统(格式化),否则也会报错。
parted中所有的操作都是立即生效,没有保存生效的概念。
分配swap分区
分区,并修改swap分区ID fdisk /dev/sdb
格式化 mkswap/dev/sdb1
使用swap分区 swapon/dev/sdb1
关闭swap分区 swapoff/dev/sdb1
自动挂载,修改配置文件 /dev/sdb1 swap swap defaults 0 0
free #查看swap分区的大小
高级文件系统管理
grep CONFIG_QUOTA/boot/config-2.6.32-279.el6.i686
#查看内核是否支持磁盘配额,一般都支持
rpm –qa | grep quota #查看系统是否安装了quota工具,默认已安装
要支持磁盘配额的分区必须开启磁盘配额功能,这个功能需手工开启。
磁盘配额分为用户配额和组配额。配额包括磁盘容量限制和文件个数限制。限制又包括软限制和硬限制。
宽限时间:如果用户的空间占用数处于软限制和硬限制之间,系统会在用户登录时警告用户磁盘将满,这个时间就是宽限时间,默认为7天。如果达到了宽限时间,用户的磁盘占用量还超过软限制,那么软限制就会升级为硬限制。
磁盘配额是限制普通用户在分区上使用磁盘空间和文件个数的,所以需要指定一个分区。针对的是普通用户,普通用户需要对分区有写的权限。
如果用户限制和组限制同时存在,那么哪个限制更小,哪个限制优先级更高。
mount –o remount,usrquota,grpquota /disk
#重新挂载/disk分区,并加入用户和用户组的磁盘配额功能
需永久生效,修改/etc/fstab文件,重新挂载分区或重启系统
quotacheck [选项] [分区名] #建立磁盘配额的配置文件
-a 扫描/etc/mtab文件中所有启用磁盘配额功能的分区。如果加入此参数,命令后面就不需要加入分区名了
-c 不管原有的配置文件,重新扫描并建立新的配置文件
-u 建立用户配额的配置文件,也就是生成aquota.user文件
-g 建立组配额的配置文件,会生成aquota.group文件
-v 显示扫描过程
-m 强制以读写的方式扫描文件系统,和-M类似,一般扫描根分区时使用
-f 强制扫描文件系统,并写入新的配置文件,一般扫描新添加的硬盘分区时使用
建立磁盘配置文件时需关闭SElinux
setenforce0 关闭SElinux setenforce 1 开启SElinux
sestatus #查看状态
配置文件/etc/selinux/config
如果自动扫描/分区建立配额配置文件时,因为/分区已经挂载成读写系统,而quotacheck需要先把分区挂载成只读分区,然后建立配置文件,最后再挂载回来,所以不能直接在/分区建立配置文件。这时就需要使用-m强制以读写方式扫描文件系统。
edquota [选项] [用户名或组名] #设置用户和组的配额限制
-u用户名:设定用户配额
-g组名:设定组配额
-t:设定宽限时间
-p:复制配额限制,如果已经设定好某个用户的配额限制,其他用户的配额限制如果和这个用户相同,那么可以直接复制配额限制,而不用都手工指定
Filesystem block soft hard inodes soft hard
/dev/sdb1 0 0 0 0 0 0
#分区名 已占用容量软限制 硬限制 已占用文件数 软限制 硬限制
已占用容量和已占用文件数不能修改。
edquota –p 源用户 –u 目标用户 #配额复制
quotaon [选项] [分区名] #启动配额
-a:依据/etc/mtab文件启动所有的配额分区,如果不加-a,后面一定要指定分区名
-u:启动用户配额
-g:启动组配额
-v:显示启动过程的信息
quotaoff [选项] [分区名] #关闭配额
-a:依据/etc/mtab文件关闭所有的配额分区,如果不加-a,后面一定要指定分区名
-u:关闭用户配额
-g:关闭组配额
quota [选项] [用户名或组名] #查询用户或用户组配额(选项都要写)
-u用户名:查询用户配额
-g组名:查询组配额
-v:显示详细信息
-s:以习惯单位显示容量大小
repquota [选项] [分区名] #查询文件系统配额(选项都要写)
-a:依据/etc/mtab文件查询配额,如果不加-a,就一定要加分区名
-u:查询用户配额
-g:查询组配额
-v:显示详细信息
-s:以习惯单位显示容量大小
dd if=/dev/zero of=/disk/testfile bs=1Mcount=60#建立testfile测试文件,指定大小60MB
setquota –u 用户名 容量软限制 容量硬限制 个数软限制 个数硬限制 分区名
#非交互设定用户磁盘配额(容量限制后不能加单位,默认为字节)
非交互设定用户磁盘配额在写脚本批量设置时更加方便。当然写脚本时也可以先建立一个模板用户,设定好磁盘配额,再进行配额复制,也是可以的。
LVM是Logical VolumeManager的简称,中文就是逻辑卷管理。
物理卷(PV,Physical Volume):就是真正的物理硬盘或分区。
卷组(VG,Volume Group):将多个物理卷合起来就组成了卷组,组成同一个卷组的物理卷可以是同一个硬盘的不同分区,也可以是不同硬盘上的不同分区。可以把卷组想象为一个逻辑硬盘。
逻辑卷(LV,Logical Volume):卷组是一个逻辑硬盘,硬盘必须分区之后才能使用,这个分区称作逻辑卷。逻辑卷可以格式化和写入数据。可以把逻辑卷想象成分区。
物理扩展(PE,Physical Extend):PE是用来保存数据的最小单元,数据实际上都是写入PE当中,PE的大小是可以配置的,默认是4MB。PE和基本文件系统中的block数据块非常相似。
建立LVM的步骤:
首先需要把物理硬盘分成分区,当然也可以是整块物理硬盘。
然后把物理分区建立成为物理卷,也可以直接把整块硬盘都建立为物理卷。
接下来把物理卷整合成为卷组。卷组就已经可以动态的调整大小了,可以把物理分区加入卷组,也可以把物理分区从卷组中删除。
最后就是把卷组再划分为逻辑卷,当然逻辑卷也是可以直接调整大小的。逻辑卷可以想象成分区,也需要格式化和挂载。
把物理分区建立成物理卷时,分区的ID号要改成8e。
pvcreate [设备文件名] #建立物理卷
pvscan #查看物理卷。可以看到物理卷总量,使用数量,空闲数量
pvdisplay #查看详细的物理卷状态
pvremove 设备文件名 #删除物理卷
vgcreate [选项] 卷组名 物理卷名 #建立卷组
-sPE的大小:指定PE的大小,单位可以是MB,GB等,如果不写默认PE大小是4MB
vgscan #查看系统中是否有卷组
vgdisplay #查看卷组的详细状态
vgextend 卷组名 设备文件名 #增加卷组容量
vgreduce 卷组名 设备文件名 #在卷组中删除物理卷
vgreduce –a #删除所有未使用的物理卷
vgremove 卷组名 #删除卷组
卷组删除之后,才能删除物理卷。如果有了逻辑卷,要先删除逻辑卷再删除卷组。
lvcreate [选项] [-n 逻辑卷名] 卷组名 #建立逻辑卷
-L容量:指定逻辑卷的大小,单位MB,GB,TB等
-l个数:按照PE个数指定逻辑卷大小,这个参数需要换算容量
-n逻辑卷名:指定逻辑卷名
建立完逻辑卷之后,还要格式化和挂载之后逻辑卷才能正常使用。格式化和挂载命令和操作普通分区时是一样的,逻辑卷的设备文件名是/dev/卷组名/逻辑卷名
lvscan #查看系统中是否有逻辑卷
lvdisplay #查看逻辑卷的详细信息
lvresize [选项] 逻辑卷设备文件名 #调整逻辑卷大小
-L 容量:按照容量调整大小,单位KB,MB,GB等。使用+代表增加空间,-号代表减少空间。如果直接写容量,代表设定逻辑卷大小为指定大小
-l个数:按照PE个数调整逻辑卷大小
resize2fs [选项] [设备文件名] [调整的大小] #调整分区大小
-f:强制调整
设备文件名:指定调整哪个分区的大小
调整的大小:指定把分区调整到多大,要加M,G等单位,如果不加大小,会使用整个分区
LVM的优势是不需要卸载分区,直接就能调整分区的大小。数据不会丢失
lvremove 逻辑卷设备文件名 #删除逻辑卷,要先卸载
RAID 0也叫Stripe或Striping(带区卷)。
RAID 1也叫Mirror或Mirroring(镜像卷),由两块硬盘组成。
如果先用两块硬盘组成RAID 1,再用两块硬盘组成另一个RAID 1,最后把这两个RAID 1组成RAID 0,这种RAID方法我们就称作RAID 10.那先组成RAID 0,再组成RAID 1的方法我们就称作RAID 01.
RAID 5最少需要三块硬盘组成,当然硬盘的大小也应当一致。
mdadm [模式] [RAID设备文件名] [选项]
Assemble:加入一个已经存在的阵列
Build:创建一个没有超级块的阵列
Create:创建一个阵列,每个设备具有超级块
Manage:管理阵列,如添加设备和删除损坏设备
Misc:允许单独对阵列中的设备进行操作,如停止阵列
Followor Monitor:监控RAID状态
Grow:改变RAID的容量或阵列中的数目
-s,--scan:扫描配置文件或/proc/mdstat文件,发现丢失信息
-D,--detail:查看磁盘阵列详细信息
-C,--create:建立新的磁盘阵列,就是调用Create模式
-a,--auto=yes:采用标准格式建立磁盘阵列
-n,--raid-devices=数字:使用几个硬盘或分区组成RAID
-l,--level=级别,创建RAID的级别,可以是0,1,5
-x,--spare-devices=数字:使用几个硬盘或分区组成备份设备
-a,--add 设备文件名:在已经存在的RAID中加入设备
-r,--remove 设备文件名:在已经存在的RAID中移除设备
-f,--fail 设备文件名:把某个组成RAID的设备设置为错误状态
-S,--stop:停止RAID设备
-A,--assemble:按照配置文件加载RAID
命令模式建立RAID5
mdadm --create --auto=yes /dev/md0 --level=5--raid-devices=3 --spare-devices=1 /dev/sdb5 /dev/sdb6 /dev/sdb7 /dev/sdb8 #创建/dev/md0,有等号只能用全称
mdadm –D /dev/md0 #查看新建立的/dev/md0
cat /proc/mdstat #查看RAID相关信息
mkfs –t ext4 /dev/md0 #格式化
mkdir /raid #建立挂载点
mount /dev/md0 /raid #挂载/dev/md0
mount #查看挂载是否正常
echo Device /dev/sdb[5-8] >>/etc/mdadm.conf
#建立/etc/mdadm.conf配置文件,并把组成RAID的分区设备文件名写入。如果有多个RAID,要把所有组成RAID的设备都放入配置文件,否则RAID设备重启后会丢失。比如组成RAID10,就既要把分区设备文件名放入此文件,也要把组成RAID 0的RAID 1设备文件名放入
mdadm –Ds >> /etc/mdadm.conf #查询和扫描RAID信息,并追加进/etc/mdadm.conf文件
cat /etc/mdadm.conf #查看文件内容
vi /etc/fstab #设置开机自动挂载
mdadm –S /dev/md0 #停止RAID,要先卸载
#删除RAID,要删除/etc/fstab和/etc/mdadm.conf内相关内容
mdadm –As /dev/md0 #启动RAID,要记得挂载
mdadm /dev/md0 –f /dev/sdb7 #模拟/dev/sdb7分区报错
mdadm –D /dev/md0 #查看RAID状态,备份分区已自动替换
mdadm /dev/md0 –r /dev/sdb7 #移除错误分区
mdadm /dev/md0 –a /dev/sdb9 #添加新的备份分区
shell命令解释器
Shell的两种主要语法类型有Bourne和C,这两种语法彼此不兼容。Bourne家族主要包括sh、ksh、Bash、psh、zsh;C家族主要包括:csh、tcsh(Bash和zsh在不同程度上支持csh的语法),通过/etc/shells文件查询Linux支持的Shell。
echo [选项] [输出内容]
-e 支持反斜线控制的字符转换
-n 取消输出后行末的换行符号(就是内容输出后不换行)
-e支持的控制字符
\\ 输出\本身
\a 输出警告音
\b 退格键,也就是向左删除键
\c 取消输出行末的换行符,和-n一样
\e ESCAPE键
\f 换页符
\n 换行符
\r 回车键
\t 制表符,也就是Tab键
\v 垂直制表符
\0nnn 按照八进制ASCII码表输出字符。其中0为数字零,nnn是三位八进制数
\xhh 按照十六进制ASCII码表输出字符。其中hh是两位十六进制数
echo –e “\e[1;31m abc \e[0m”
\e[1代表颜色输出开始,\e[0m代笔颜色输出结束,为标准格式
字体颜色:30=黑色31=红色 32=绿色 33=*** 34=蓝色 35=洋红 36=青色 37=白色
背景颜色:40=黑色 41=红色 42=绿色 43=*** 44=蓝色 45=洋红 46=青色 47=白色
shell脚本的运行:赋予执行权限,用绝对路径或相对路径运行或者直接bash+文件名运行。
cat –A 文件名 #显示文件所有内容
dos2unix 文件名 #转换windows格式为linux格式
history [选项] [历史命令保存文件]
-c清空历史命令
-w 把缓存中的历史命令写入历史命令保存文件,如果不手工指定历史命令保存文件,则放入默认历史命令保存文件~/.bash_history中
显示历史命令具体时间:
HISTTIMEFORMAT="%Y-%m-%d%H:%M:%S"
exportHISTTIMEFORMAT
/etc/profile为设置历史命令保存条数文件
使用上下箭头调用以前的历史命令;
使用“!n”重复执行第n条历史命令;
使用“!!”重复执行上一条命令;
使用“!字串”重复执行最后一条以该字串开头的命令;
使用“!$”重复上一条命令的最后一个参数
alias #查询命令别名
alias 别名=‘原命令’ #设定命令别名
unalias #取消别名
想让别名永久生效,可以把别名写入环境变量配置文件“~/.bashrc”
命令执行时的顺序:
第一顺位执行用绝对路径或相对路径执行的命令
第二顺位执行别名
第三顺位执行bash的内部命令
第四顺位执行按照$PATH环境变量定义的目录查找顺序找到的第一个命令
Bash中快捷键
ctrl+A 把光标移动到命令行开头
ctrl+E 把光标移动到命令行结尾
ctrl+C 强制终止当前的命令
ctrl+L 清屏,相当于clear命令
ctrl+U 删除或剪切光标之前的命令
ctrl+K 删除或剪切光标之后的命令
ctrl+Y 粘贴ctrl+U或ctrl+K剪切的内容
ctrl+R 在历史命令中搜索
ctrl+D 退出当前终端
ctrl+Z 暂停,并放入后台
ctrl+S 暂停屏幕输出
ctrl+Q 恢复屏幕输出
ls || echo no && echo yes #不能执行,命令执行符为文本流操作
程序语言的特征:
拥有变量;
拥有流程控制语句;
拥有数值运算方法;
拥有函数。
HTML为超文本标记语言,只是语句,没有语言特征。
grep [选项] “搜索内容” 文件名
-A数字:列出符合条件的行,并列出后续的n行
-B数字:列出符合条件的行,并列出前面的n行
-c:统计找到的符合条件的字符串的次数
-i:忽略大小写
-n:输出行号
-v:反向查找
--color=auto:搜索出的关键字用颜色显示
find命令是在系统当中搜索符合条件的文件名,如果需要模糊查询,使用通配符进行匹配,搜索时文件名是完全匹配。
grep命令是在文件当中搜索符合条件的字符串,如果需要模糊查询,使用正则表达式进行匹配,搜索时字符串是包含匹配。
通配符:
? 匹配一个任意字符
* 匹配0个或任意多个字符,也就是可以匹配任何内容
[] 匹配括号中任意一个字符
[-] 匹配括号中任意一个字符,-代表一个范围
[^] 逻辑非,表示匹配不是括号内的一个字符
ls [^0-9]* #匹配不以数字开头的文件
grep “^[0-9]” abc #查找abc中以数字开头的行
Bash中特殊符号
‘’ 单引号,在单引号中所有的特殊符号都没有特殊含义,如“$”和“`”
“” 双引号,在双引号中特殊符号都没有特殊含义,但是“$”“`”和“\”例外,拥有“调用变量的值”“引用命令”和“转义符”的特殊含义
`` 反引号,反引号括起来的内容是系统命令,在Bash中会先执行它,和$()作用一样
$() 和反引号作用一样,用来引用系统命令
() 用于一串命令执行时,()中的命令会在子shell中运行
{} 用于一串命令执行时,{}中的命令会在当前Shell中执行,也可以用于变量变形与替换
[] 用于变量的测试
# 在Shell脚本中,#开头的行代表注释
$ 用于调用变量的值,如需要调用变量name的值时,用$name的方式得到变量的值
\ 转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符
父Shell和子Shell:在Bash中,是可以调用新的Bash的。
pstree #查看进程树
用于一串命令的执行,小括号和大括号的区别:
()执行一串命令时,需要重新开一个子Shell进行执行,{}执行一串命令时,是在当前Shell执行;
()最后一个命令可以不用分号,{}最后一个命令要用分号;
()里的各命令不必和括号有空格,{}的第一个命令和左括号之间必须要有一个空格;
()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开;
()和{}里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令。
(name=liming;echo $name;set) #当前Shell操作,新建子Shell;命令结束,子Shell消失
{ name=liming;echo $name;} #当前Shell操作,直接影响当前Shell
定义变量时,需要遵守的原则:
变量名称可以由字母、数字和下划线组成,但是不能以数字开头;
在Bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必须修改指定变量类型为数值型,如a=1,b=2,c=$a+b$,echo $c,结果为1+2
变量用等号连接值,等号左右两侧不能有空格;
变量的值如果有空格,需要使用单引号或双引号。其中双引号括起来的内容“$”“\”和反引号都有特殊含义,而单引号括起来的都是普通字符;
在变量的值中,可以使用“\”转义符;
如果需要增加变量的值,可以进行变量值的叠加。格式为“$变量名”或${变量名}。如test=”$test”456或test=${test}789;
如果是把命令的结果作为变量值赋予变量,则需要使用反引号或$()包含命令,如test=$(date);
环境变量名建议大写,便于区分。
用户自定义变量(本地变量):这种变量是最常见的变量,由用户自定义变量名和变量的值。
环境变量:这种变量中主要保存的是和系统操作环境相关的数据,比如当前登录用户,用户的家目录,命令提示符等。环境变量的变量名可以自由定义,但是一般对系统起作用的环境变量的变量名是系统预先设定好的。对子shell都生效,对父shell不生效。
位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
set [选项]
-u:如果设定此选项,调用未声明变量时会报错(默认无任何提示)
-x:如果设定此选项,在命令执行之前,会把命令先输出一次
#直接使用set命令,会查询系统中所有的变量,包含用户自定义变量和环境变量
unset 变量名 #删除变量
export 变量名=变量值 #声明环境变量
env #只查看环境变量
PATH变量:系统查找命令的路径
PATH变量的值是用“:”分割的路径,这些路径就是系统查找命令的路径。也就是说当输入一个程序名,如果没有写入路径,系统就会到PATH变量定义的路径中去寻找,是否有可以执行的程序。如果找到则执行,否则会报“命令没有发现”的错误。
把自己的脚本拷贝到PATH变量定义的路径中,自己写的脚本也可以不输入路径而直接运行;或者修改PATH变量的值,通过变量的叠加实现,如PATH=”$PATH”:/root/sh
PS1变量:命令提示符设置
\d:显示日期,格式为“星期 月 日”
\H:显示完整的主机名,默认主机名“localhost.localdomain”
\h:显示简写主机名。默认主机名“localhost”
\t:显示24小时制时间,格式为“HH:MM:SS”
\T:显示12小时制时间,格式为“HH:MM:SS”
\A:显示24小时制时间,格式为“HH:MM”
\@:显示12小时制时间,格式为“HH:MM am/pm”
\u:显示当前用户名
\v:显示Bash的版本信息
\w:显示当前所在目录的完整名称
\W:显示当前所在目录的最后一个目录
\#:执行的第几个命令
\$:提示符。如果是root用户会显示提示符为“#”,如果是普通用户会显示提示符为“$”
在PS1变量中,如果是可以解释的符号,如“\u”“\h”等,则显示这个符号的作用。如果是不能解释的符号,如“@”或“空格”,则原符号输出。
PS1变量的值要用单引号包含,否则设置不生效。
LANG变量定义了Linux系统的主语系环境
locale –a #查看Linux支持的语系
locale #查看当前系统语系
通过/etc/sysconfig/i18n定义系统的默认语系
默认语系是下次重启之后系统所使用的语系,而当前系统语系是当前系统使用的语系。如果系统重启,会从默认语系配置文件/etc/sysconfig/i18n中读出语系,然后赋予变量LANG让这个语系生效。也就是说,LANG定义的语系只对当前系统生效,要想永久生效就要修改/etc/sysconfig/i18n文件。
如果是在图形界面中,或者是使用远程连接工具,只要设置了语系,那么就可以正确显示中文的。如果是纯字符界面,是不能显示中文的,因为Linux的纯字符界面是不能显示中文这么复杂的编码的。如果我们非要在纯字符界面显示中文,那么只能安装中文插件,如zhcon等。
位置参数变量
$n n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要用大括号包含,如${10}
$* 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体
$@ 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待
$# 这个变量代表命令行中所有参数的个数
$n要在执行程序的时候输入参数(./test.sh 12 34 45),只有写程序的人知道程序是做什么的。
预定义变量
$? 最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体的数由命令自己决定),则证明上一个命令执行不正确了
$$ 当前进程的进程号(PID)
$! 后台运行的最后一个进程的进程号(PID)
read [选项] [变量名] #接收键盘输入
-p “提示信息”:在等待read输入时,输出提示信息
-t 秒数:read命令会一直等待用户输入,使用此选项可以指定等待时间
-n 字符数:read命令只接受指定的字符数,就会执行
-s:隐藏输入的数据,适用于机密信息的输入
变量名可以自定义,如果不指定变量名,会把输入保存入默认变量REPLY;
如果只提供了一个变量名,则整个输入行赋予该变量;
如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,而命令行上的最后一个变量取得剩余的所有字。(变量数量少于赋值数量,最后一个变量为带空格字符串变量)
declare [+/-][选项] 变量名 #声明变量类型,所有变量的默认类型为字符串型
- 给变量设定类型属性
+ 取消变量的类型属性
-a 将变量声明为数组型
-i 将变量声明为整数型
-r 将变量声明为只读变量。一旦设置为只读变量,既不能修改变量的值,也不能删除变量,甚至不能通过+r取消只读属性
-x 将变量声明为环境变量
-p 显示指定变量的被声明类型
declare –x test=123 #声明环境变量,export也是通过declare命令声明的
数组就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标。组成数组的各个变量成为数组的分量,也称为数组的元素,有时也称为下标变量。
变量和数组都是用来保存数据的,只是变量只能赋予一个数据值,一旦重复复制,后一个值就会覆盖前一个值。而数组是可以赋予一组相同类型的数据值。
数组的下标是从0开始的,在调用数组值时,需要使用${数组[下标]}的方式来读取。
只要在定义变量时采用了“变量名[下标]”的格式,这个变量就会被系统认为是数组型了,不用强调声明。
name[0]=”li ming” 定义数组
echo ${name[*]} 显示数组所有分量
数值运算: declare -i cc=$aa+$bb
dd=$(expr$aa + $bb) #加号左右两侧必须有空格
letee=$aa+$bb
ff=$(($aa+$bb))
gg=$[$aa+$bb]
shell常用运算符
赋值、运算且赋值
运算符优先级表明在每个表达式或子表达式中哪一个运算对象首先被求值,数值越大优先级越高,具有较高优先级级别的运算符先于较低级别的运算符进行求值运算。小括号可以调整优先级。
变量的测试与内容置换
变量变换方式
source 配置文件 或 . 配置文件 #修改配置文件不重启就可以生效
.作用:隐藏文件,当前目录,source
在Linux系统登录时主要生效的环境变量配置文件
/etc/profile
/etc/profile.d/*.sh
~/.bash_profile
无密码登录,如su
~/.bashrc
/etc/bashrc
环境变量配置文件调用过程
在用户登录过程先调用/etc/profile文件
USER变量:根据登录的用户,给这个变量赋值(就是让USER变量的值是当前用户)
LOGNAME变量:根据USER变量的值,给这个变量赋值
MAIL变量:根据登录的用户,定义用户的邮箱为/var/spool/mail/用户名
PATH变量:根据登录用户的UID是否为0,判断PATH变量是否包含/sbin、/usr/sbin 和/usr/local/sbin这三个系统命令目录
HOSTNAME变量:更改主机名,给这个变量赋值
HISTSIZE变量:定义历史命令的保存条数
umask:定义umask默认权限,/etc/profile文件中的umask权限是在“有用户登录过程(也就是输入了用户名和密码)”时才会生效
调用/etc/profile.d/*.sh文件,也就是调用/etc/profile.d/目录下所有以.sh结尾的文件。
由/etc/profile文件调用/etc/profile.d/*.sh文件
这个目录中所有以.sh结尾的文件都会被/etc/profile文件调用,这里最常用的就是lang.sh文件,而这个文件又会调用/etc/sysconfig/i18n文件。
由/etc/profile文件调用~/.bash_profile文件
调用了~/.bashrc文件
在PATH变量后面加入了“:$HOME/bin”这个目录。如果在自己的家目录中建立bin目录,然后把自己的脚本放入“~/bin”目录,就可以直接执行脚本,而不用通过目录执行了。
由~/.bash_profile文件调用~/.bashrc文件
定义默认别名
调用/etc/bashrc
由~/.bashrc调用了/ect/bashrc文件
PS1变量:用户提示符,永久修改提示符
umask:定义umask默认权限,此文件的umask是针对“没有登录过程(也就是不需要输入用户名和密码时,如从一个终端切换到另一个终端,或进入子Shell)”时生效的。如果是“有用户登录过程”,则是/etc/profile文件中的umask生效。
PATH变量:会给PATH变量追加值,也是在“没有登录过程”时才调用。
调用/etc/profile.d/*.sh文件,也是在“没有用户登录过程”时才调用。在“有用户登录过程”时,/etc/profile.d/*.sh文件已经被/etc/profile文件调用过了。
如果修改打算对所有用户生效的,那么可以放入/etc/profile环境变量配置文件;如果修改只是给自己使用的,那么可以放入~/.bash_profile或~/.bashrc这两个配置文件中的任一个。
如果误删除了这些环境变量,如删除了/etc/bashrc文件或/~/.bashrc文件,这些文件中配置就会生效,提示符会变成:-bash-4.1#
在用户退出登录时,只会调用一个环境变量配置文件,就是~/.bash_logout。这个文件默认没有写入任何内容,可是如果想在退出登录时执行一些操作,比如清除历史命令,备份某些数据,就可以把命令写入这个文件。
还有一些环节变量配置文件,最常见的就是~/.bash_history文件,也就是历史命令保存文件。
在登录tty1-tty6这六个本地终端时,会有几行欢迎界面,这些欢迎信息保存在/etc/issue文件中。
支持的转义符可以通过man agetty命令查询:
\d 显示当前系统日期
\s 显示操作系统名称
\l 显示登录的终端号
\m 显示硬件体系结构,如i686等
\n 显示主机名
\o 显示域名
\r 显示内核版本
\t 显示当前系统时间
\u 显示当前登录用户的序列号
/etc/issue是在本地终端登录显示欢迎信息的,如果是在远程登录需要显示欢迎信息,则需要配置/etc/issue.net文件。在/etc/issue文件中支持的转义符,在/etc/issue.net文件中不能使用。ssh远程登录是否显示/etc/issue.net文件中的欢迎信息,是由ssh的配置文件/etc/ssh/sshd_config决定的,需要加入Banner /etc/issue.net,才能显示。
/etc/motd文件中也是显示欢迎信息的,这个文件和/etc/issue及/etc/issue.net文件的区别是:/etc/issue及/etc/issue.net是在用户登录之前显示欢迎信息,而/etc/motd是在用户输入用户名和密码。正确登录之后显示欢迎信息的。在/etc/motd文件中的欢迎信息,不论是本地登录,还是远程登录都可以显示。
stty 关键字 快捷键 #定义快捷键
stty intr ^p #定义ctrl+p快捷键为强制终止,^只要手工输入即可
用来在文件当中搜索字符串的命令,如grep、awk、sed等命令可以支持正则表达式,而在系统当中搜索文件的命令,如ls、find、cp这些命令不支持正则表达式。
基础正则表达式
* 前一个字符匹配0次或任意多次
. 匹配除了换行符外任意一个字符
^ 匹配行首
$ 匹配行尾
[] 匹配括号中指定的任意一个字符,只匹配一个字符
[^] 匹配除括号中的字符以外的任意一个字符
\ 转义符。用于取消特殊符号的含义
\{n\} 表示其前面的字符恰好出现n次
\{n,\} 表示其前面的字符出现不小于n次
\{n,m\} 表示其前面的字符至少出现n次,最多出现m次
.* 标准匹配任意字符
\.$ 匹配以.结尾的行
^$ 匹配空白行
扩展正则表达式
在正则表达式中可以支持一些元字符(扩展元字符),如“+”“?”“|”“()”,但grep命令默认不支持,要想支持这些元字符,必须使用egrep命令或grep –E选项。
+ 前一个字符匹配1次或任意多次
? 前一个字符匹配0次或1次
| 匹配两个或多个分支选择,如“was|his”,一般与()同时使用
() 匹配其整体为一个字符,即模式单元,可以理解为由多个单个字符组成的大字符。
cut [选项] 文件名(cut列提取命令)
-f列号:提取第几列
-d分隔符:按照指定分隔符分割列
-c 字符:不依赖分隔符来区分列,而是通过字符范围(行首为0)来进行字段提取。“n-”表示从第n个字符到行尾;“n-m”从第n个字符到第m个字符;“-m”表示从第1个字符到第m个字符。
cut命令的默认分隔符是制表符,也就是“tab”键,不支持空格符。
想提取多列,只要列号直接用“,”分开即可。
cut -d ":" -f 1,3 /etc/passwd #以“:”为分隔符,提取/etc/passwd文件的第一列和第三列
grep "s..d" test.test #匹配在s和d两个字母之间有两个字符的单词
grep "^[^a-zA-Z]" test.test #匹配非字母开头的行
printf ‘输出类型输出格式’ 输出内容 #printf格式化输出
输出类型: %ns:输出字符串,n是数字指代输出几个字符
%ni:输出整数,n是数字指代输出几个数字
%m.nf:输出浮点数,m和n是数字,指代输出的整数位数和小数位数
输出格式: \a:输出警告声音
\b:输出退格键,也就是Backspace键
\f:清除屏幕
\n:换行
\r:回车,也就是Enter键
\t:水平输出退格键,也就是Tab键
\v:垂直输出退格键,也就是Tab键
printf ‘%s’ $(cat student.txt) #printf后只能跟内容,不支持管道符
awk ‘条件1{动作1} 条件2{动作2}…’ 文件名 #awk编程
一般使用关系表达式作为条件,如:
x>10 判断变量x是否大于10
x==y 判断变量x是否等于变量y
动作: 格式化输出
流程控制语句
加入了条件之后,只有条件成立动作才会执行,如果条件不满足,则动作不运行。awk是列提取命令,但也要按行来读入的。命令的执行过程是:
如果有BEGIN条件,则先执行BEGIN定义的动作;
如果没有BEGIN条件,则读入第一行,把第一行的数据依次赋予$0、$1、$2等变量。其中$0代表此行的整体数据,$1代表第一字段,$2代表第二字段。
依据条件类型判断动作是否执行。如果条件符合,则执行动作,否则读入下一行数据;如果没有条件,则每行都执行动作。
读入下一行数据,重复执行以上步骤。
awk内置变量
$0 代表目前awk所读入行的整行数据
$n 代表目前读入行的第n个字段
NF 当前行拥有的字段(列)总数
NR 当前awk所处理的行,是总数据的第几行
FS 用户定义分隔符。awk的默认分隔符是任何空格,如果想要使用其他分隔符(如:),就需要FS变量定义
ARGC 命令行参数个数
ARGV 命令行参数数组
FNR 当前文件中的当前记录数(对输入文件起始为1)
OFMT 数值的输出格式(默认为%.6g)
OFS 输出字段的分隔符(默认为空格)
ORS 输出记录的分隔符(默认为换行符)
RS 输入记录的分隔符(默认为换行符)
df –h | awk ‘{print $1 “\t” $3}’
#awk的分隔符支持空格,print=printf‘\n’,awk和printf同时使用,printf要用双引号
awk 'BEGIN{print "this is atranscript"}END{print "the end"}{print $2 "\t" $6}'stu.txt
#在开头结尾输入信息
awk '$2 ~ /Sc/ {print $6}' stu.txt
#如果第二字段包含“Sc”字符,则打印第六字段数据
cat /etc/passwd | grep"/bin/bash" | awk 'BEGIN{FS=":"}{print $1 "\t"$3}'
#以“:”为分隔符,查询可以登录用户的用户名和UID
awk'NR==2{php1=$3}NR==3{php2=$3}NR==4{php3=$3;totle=php1+php2+php3;print"totle php is" totle}' stu.txt
在awk编程中,因为命令语句非常长,在输入格式时需要注意:
多个条件{动作}可以用空格分隔,也可以用回车分割;
在一个动作中,如果需要执行多个命令,需要用“;”分割,或用回车分割;
在awk中,变量的赋值与调用都不需要加入“$”符;
条件中判断两个值是否相同,请使用“==”以便和变量赋值进行区分。
awk编程也允许在编程时使用函数,awk函数的定义方法:
function 函数名 (参数列表){函数体}
awk'function test(a,b){print a "\t" b}{test($2,$6)}' stu.txt
#定义函数test,包含两个参数,函数体的内容是输出这两个参数的值,调用函数test,并向两个参数传递值
对于小的单行程序来说,将脚本作为命令行自变量传递给awk是非常简单的,而对于多行程序就比较难处理。当程序是多行的时候,使用外部脚本是很适合的,首先在外部文件中写好脚本,然后可以使用awk的-f选项,使其读入脚本并且执行。
vipass.awk
BEGIN{FS=":"}
{print $1"\t" $3}
awk -f pass.awk/etc/passwd
sed主要是用来将数据进行选取、替换、删除、新增的命令。与vi作用相同,但vi必须人机交互,sed可以写在程序里自动执行。
sed [选项]‘[动作]’文件名
选项:-n:一般sed命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕
-e:允许对输入数据应用多条sed命令编辑
-f 脚本文件名:从sed脚本中读入sed操作。和awk命令的-f非常相似
-r:在sed中支持扩展正则表达式
-i:用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出
动作:a \:追加,在当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾需要用“\”代表数据未完结
c \:行替换,用c后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾需用“\”代表数据未完结
i \:插入,在当前行前插入一行或多行。插入多行时,除最后一行外,每行末尾需要用“\”代笔数据未完结
d:删除,删除指定的行
p:打印,输出指定的行
s:字符替换,用一个字符串替换另外一个字符串。格式为“行范围s/旧字串/新字串/g”(和vim中的替换格式类似)
sed所做的修改并不会直接改变文件的内容(可以用管道符接收命令的输出),而是把修改结果只显示到屏幕上,除非使用“-i”选项才会直接修改文件。
sed -n '2p' stu.txt #打印文件第二行
sed '2i hello \
> world' stu.txt #在第二行前插入两行数据
sed -e 's/liming//g;s/Gao//g' stu.txt #同时把“Liming”和“Gao”替换为空
sort [选项] 文件名(字符排命令序)
-f:忽略大小写
-b:忽略每行前面的空白部分
-n:以数值型进行排序,默认使用字符串型排序
-r:反向排序
-u:删除重复行,就是uniq命令
-t:指定分隔符,默认分隔符是制表符
-kn[,m]:按照指定的字段范围排序。从第n字段开始,m字段结束(默认到行尾)
sort -n -t ":" -k 3,3 /etc/passwd #指定分隔符是“:”,只用第三字段排序
uniq [选项] 文件名 #取消重复行,和“sort –u”作用一样,不改变原文件
-i忽略大小写
wc [选项] 文件名
-l 只统计行数
-w 只统计单词数
-m 只统计字符数
test 选项 文件名 / [ 选项 文件名 ] #条件判断
按照文件类型
-b文件:判断该文件是否存在,并且是否为块设备文件(是块设备文件为真)
-c文件:判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真)
-d文件:判断该文件是否存在,并且是否为目录文件(是目录为真)
-e文件:判断该文件是否存在(存在为真)
-f文件:判断该文件是否存在,并且是否为普通文件(是普通文件为真)
-L文件:判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真)
-p文件:判断该文件是否存在,并且是否为管道文件(是管道文件为真)
-s文件:判断该文件是否存在,并且是否为非空(非空为真)
-S文件:判断该文件是否存在,并且是否为套接字文件(是套接字文件为真)
[ -d /root/sh/ ]&& echo yes || echo no
存储设备为块设备文件,终端为字符设备文件,MySQL为套接字文件
按照文件权限
-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号一致,用于判断硬链接
[/root/test/stu.txt -ef /tmp/stus.txt ] && echo yes || echo no
两个整数之间比较
整数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(小于等于为真)
[ 23 -ge 22 ]&& echo y || echo n
字符串的判断
-z字符串:判断字符串是否为空(为空返回为真)
-n字符串:判断字符串是否为非空(非空返回为真)
字串1 == 字串2:判断字符串1是否和字符串2相等(相等返回真)
字串1 != 字串2:判断字符串1是否和字符串2不相等(不相等返回真)
[-z "$name" ] && echo y || echo n
["$aa" == "$bb" ] && echo y || echo n
多重条件判断
判断1 –a 判断2:逻辑与,判断1和判断2都成立,最终的结果才为真
判断1 –o 判断2:逻辑或,判断1和判断2有一个成立,最终的结果就为真
! 判断:逻辑非,使原始的判断式取反
[-n "$aa" -a "$aa" -gt 2 ] && echo y || echo n
[ ! -n"$aa" ] && echo y || echo n #!和-n之间必须有空格
单分支if条件语句
if [ 条件判断式 ];then
程序
fi
if [ 条件判断式 ]
then
程序
fi
单分支条件语句需要注意:
if语句使用fi结尾,和一般语言使用大括号结尾不同;
[条件判断式 ]就是使用test命令判断,中括号和条件判断式之间必须有空格;
then后面跟符合条件之后执行的程序,可以放在[]之后,用“;”分割,也可以换行写入
双分支if条件语句
if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的另一个程序
fi
备份
#!/bin/bash
ntpdate asia.pool.ntp.org&>/dev/null #同步系统时间
date=$(date +%y%m%d)/date=$(date +F%) #把系统时间按年月日格式赋予变量date
size=$(du -sh /etc)
mkdir/tmp/dbback &>/dev/null
echo"Date is : $date" > /tmp/dbback/db.txt
echo"size is : $size" >> /tmp/dbback/db.txt
cd/tmp/dbback
tar-zcf etc-$date.tar.gz /etc db.txt &>/dev/null
rm-rf /tmp/dbback/db.txt
判断apache是否启动
#!/bin/bash
port=$(nmap -sT 192.168.216.205 | grep tcp| grep http | awk '{print $2}')
if [ "$port" == "open"]
then
echo"$(date) httpd is ok!" >> /tmp/httpd-acc.log
else
/etc/rc.d/init.d/httpdrestart &>/dev/null
echo"$(date) httpd reboot" >> /tmp/httpd-acc.log
fi
nmap –sT 域名或IP
-s扫描
-T扫描所有开启的TCP端口
a=$(netstat -tlun | grep tcp | awk '{print$4}' | grep ":80$")
a=$(ps aux | grep httpd | grep -v grep)
用netstat –tlun和ps aux判断不准确,服务死机卡住不能判断;用nmap判断,速度慢,占用系统资源。用ps aux抓进程,程序名不能包含进程名。
多分支if条件语句
if[ 条件判断式1 ]
then
当条件判断式1成立时,执行程序1
elif[ 条件判断式2 ]
then
当条件判断式2成立时,执行程序2
……
else
当所有条件都不成立时,最后执行此程序
fi
多分支case条件语句
case语句只能判断一种条件关系,而if语句可以判断多种条件关系
case$变量名 in
“值1”)
如果变量的值等于1,则执行程序1
;;
“值2”)
如果变量的值等于2,则执行程序2
;;
……
*)
如果变量的值不是以上的值,则执行此程序
;;
esac
case语句需注意:
case语句,会取出变量中的值,然后与语句体中的值逐一比较。如果数值符合,则执行对应的程序,如果数值不符,则依次比较下一个值。如果所有的值都不符合,则执行“*)”中的程序(*代表所有其他值);
case语句以“case”开头,以“esac”结尾;
每一个分支程序之后要通过“;;”双分号结尾,代表该程序段结束。
for循环是固定循环,也就是在循环时已经知道需要进行几次的循环,有时也把for循环称为计数循环。
for 变量 in 值1 值2 值3 ……
do
程序
done
此语法中for循环的次数,取决于in后面值的个数(空格分隔),有几个值就循环几次,并且每次循环都把值赋予变量。
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
初始值:在循环开始时,需要给某个变量赋予初始值,如i=1;
循环控制条件:用于指定变量循环的次数,如i<=100,则只要i的值小于等于100,循环就会继续;
变量变化:每次循环之后,变量该如何变化,如i=i+1.代表每次循环之后,变量i的值都加1
1加到100的和
#!/bin/bash
s=0
for (( i=1;i<=100;i=i+1 ))
do
s=$(($s+$i ))
done
echo "The sum of 1+2+…+100 is:$s"
批量添加用户
#!/bin/bash
read -p "Please inputuser name:" -t 30 name
read -p "Please input the number of users:" -t 30num
read -p "Please input the password of users:" -t 30pass
if [ -n "$name" -a -n "$num" -a -n"$pass" ]
then
y=$(echo$num | sed 's/^[0-9]*$//g')
if [ -z"$y" ]
then
for((i=1;i<=$num;i=i+1))
do
/usr/sbin/useradd"$name$i" &>/dev/null
echo$pass | /usr/bin/passwd --stdin "$name$i" &> /dev/null
chage–d 0 “$name$i”
done
else
echo"Error!"
fi
else
echo"Please input something!"
fi
批量删除用户
#!/bin/bash
user=$(cat /etc/passwd | grep "/bin/bash" |grep -v "root" | cut -d ":" -f 1)
for i in $user
do
userdel-r $i
done
对while循环来讲,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。
while [ 条件判断式 ]
do
程序
done
#!/bin/bash
i=1
s=0
while [ $i -le 100 ]
do
s=$(($s+$i))
i=$(($i+1))
done
echo "The sum is :$s"
until循环和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序,一旦循环条件成立,则终止循环。
until [ 条件判断式 ]
do
程序
done
#!/bin/bash
i=1
s=0
until [ $i -gt 100 ]
do
s=$(($s+$i))
i=$(($i+1))
done
echo "The sum is :$s"
函数
function 函数名(){
程序
}
#!/bin/bash
function sum () {
s=0
for ((i=0;i<=$1;i=i+1 ))
do
s=$(($i+$s ))
done
echo"The sum of 1+2+...+$1 is :$s"
}
read -p "Please input a number :" -t 30 num
y=$(echo $num | sed 's/[0-9]//g')
if [ -z "$y" ]
then
sum$num
else
echo"Error!Please input a number!"
fi
特殊流程控制语句
exit语句
系统是有exit语句的,用于退出当前用户的登录状态。可是在shell脚本中,exit语句是用来退出当前脚本的。也就是说,在shell脚本中,只要碰到了exit语句,后续的程序就不再执行,而直接退出脚本。
exit [返回值]
如果exit命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。可以通过查询$?这个变量,来查看返回值。如果exit之后没有定义返回值,脚本执行之后的返回值是执行exit语句之前,最后执行的一条命令的返回值。
当程序执行到break语句时,会结束整个当前循环;而continue语句也是结束循环的语句,不过continue语句结束单次当前循环,而下次循环会继续。
#!/bin/bash
for (( i=1;i<=10;i=i+1 ))
do
if[ "$i" -eq 4 ]
then
break
fi
echo$i
done
#!/bin/bash
for (( i=1;i<=10;i=i+1 ))
do
if[ "$i" -eq 4 ]
then
continue
fi
echo$i
done
按照指定ip地址重启服务器(调用expect语言,使用tcl语法)
#!/bin/bash
read -p "input password:" -s pass
for host in $(cat /root/sh/ip.log)
do
expect-c "
#开启expext语言
spawn/usr/bin/ssh $host shutdown -r now
#利用spawn语法,执行ssh登录,并重启
settimeout 30
#设置超时时间
expect{
\"*yes/no*\"{send \"yes\r\";exp_continue}
#执行spawn语法,当碰到“yes/no”关键字时,发送“yes回车”
\"*password*\"{send \"$pass\r\";}
#当执行spawn语法,碰到“password”关键字时,发送密码
}
expecteof;"
#结束expect语言
done
自动ping指定ip,统计丢包率
#!/bin/bash
for i in $(cat /root/sh/ip.log)
do
aa=$(ping -c 3 $i | grep ttl | wc -l)
bb=$(( 3 - $aa ))
cc=$(echo "$bb 3" | awk'{printf "%3.2f% \n", $1/$2*100}')
echo "$i的丢包率是 $cc"
done
四则计算器
#!/bin/bash
read -t 30 -p "Please input num1: " num1
read -t 30 -p "Please input num2: " num2
read -t 30 -p "Please input a operator: " ope
if [ -n "$num1" -a -n "$num2" -a -n"$ope" ]
then
test1=$(echo $num1 | sed 's/[0-9]//g')
test2=$(echo $num2 | sed 's/[0-9]//g')
if [ -z "$test1"-a -z "$test2" ]
then
if [ "$ope" == '+' ]
then
sum=$(( $num1 +$num2 ))
elif [ "$ope" == '-' ]
then
sum=$(( $num1 -$num2 ))
elif ["$ope" == '*' ]
then
sum=$(( $num1 * $num2 ))
elif [ "$ope" == '/' ]
then
sum=$(( $num1 /$num2 ))
else
echo"Please enter a valid symbol"
exit 10
fi
else
echo "Please enter a valid value"
exit 11
fi
else
echo"qing shuru neirong"
exit 12
fi
echo " $num1 $ope $num2 : $sum"
转载于:https://blog.51cto.com/lt519/1702969