马哥培训第三周笔记 shell脚本编程基础 bash配置文件 find命令 打包和压缩工具

shell脚本编程基础

上面的标题中出现了几个词语,shell、脚本、编程还有基础,基础是什么意思大家都懂,其他几个代表什么呢?

shell:在前面的学习中已经提到过,shell可以解释成“壳”,其作用是在linux系统中,当用户键入命令并回车执行后,对命令进行翻译(或者说“解释”),从而把用户输入的命令转换成机器所能理解的形式,从而完成用户的需求。

脚本:将多个命令串联在一起执行,完成比较复杂的操作要求,起到避免操作人员每次都要重复输入大段的命令的作用,就可以称之为脚本,也就是说,脚本是命令的组合,而标题的中提到的脚本,指的就是脚本文件,也就是将多个命令组合成需要的功能,按照一定的格式要求,写入到文件中,代替每次执行命令都需要手动输入的过程,当用户需要这个功能时,直接按照系统的要求将文件中的内容“读”出来,执行即可。

编程:编程其实大家也知道,就是编程序,在这个shell编程中,可以理解为:制作脚本文件的过程,就是编程。

对于编程而言,分为:

过程式:以指令为中心,数据服务于指令。即,将用户需要实现的目的分为一步步的过程,对每个过程如何执行进行“指令”,从而最终达到目的。

对象式:以数据为中心,指令服务于数据。(shell编程是过程式,不讨论对象式)

程序运行的方式:程序都是运行在机器上的,最终不管怎么样的程序,都需要转换成机器所能理解的二进制指令,转换的方式分为两种:

编译:高级语言–>编译器–>目标代码

java,C#

解释:高级语言–>解释器–>机器代码

shell, perl, python

那么shell脚本编程的概念就很清楚了——将shell指令,按照一定的格式和逻辑关系,使用文本编辑器放到文本文件中,使其能够满足用户的某些要求,这个过程,就叫shell脚本编程。

逻辑关系的处理方式有:顺序执行、 循环执行、 选择执行。字面意思很好理解,现阶段先看看顺序执行和简单的选择执行。

shell脚本的基本结构:各种命令的组合、数据存储(变量、数组)、表达式、语句(if、for)

shell脚本的用途:1、自动化常用命;2、执行系统管理和故障排除;3、创建简单的应用程序(类似系统中的各种命令);4、处理文本或文件。

开始编程前应该掌握的各种知识点:

一、脚本具有一定的格式要求:

必须有的一行为:首行shebang机制,即#!的英文发音缩写,在#!后应该声明该脚本使用的解释器路径,虽然可以通过直接在命令行写入解释器名称跟脚本名的方法直接使用脚本,但这显然是不规范的;

提供了对#号开头的行不进行解释的功能,即,编程人员可以在脚本中对自己编写的内容进行注释,以#开头的行系统将不进行处理。同时利用这一特性也可以将一个脚本的某些行“注释”掉,从而改变一个脚本的功能。

虽然不是硬性要求,但是应该在程序正文前,对该脚本的作者,编写目的,脚本名称,编写时间,注意事项等内容进行注释(以#号开头)

二、脚本文件需要执行权限,虽然脚本文件可以通过直接在命令行写入解释器名称跟脚本名等多种方法直接使用脚本,但也是不规范的,一般使用chmod等命令为脚本文件加上执行权限。

三、脚本在使用前应在试验环境进行测试,测试成功后方可上实机进行操作,并且应使用调试命令对命令的每个步骤进行观察,检查是否有错误,相关命令有:

检测脚本中的语法错误

bash -n /path/to/some_script

调试执行

bash -x /path/to/some_script

四、hash机制,前面讲过hash机制,那么对于脚本而言,其执行过程其实类似于外部命令,也是就说hash机制同样适合脚本,当脚本被执行过一次后,系统会把路径记录在内存中,而此时如果脚本被移动到其他位置,系统仍然会寻找存放在内存中的脚本路径,而不会到硬盘上寻找,这样就会提示脚本无法找到的错误信息,此时只需要清除掉相关的hash记录,脚本就能被正确寻找到。

五、了解变量相关知识

变量,是相对于硬盘上的数据而言的,变量是储存在内存中的一段数据,而且和硬盘上的数据不同,顾名思义,变量是可以经常发生变化的,在前面我们就接触到了很多的变量,比如“$PS1”,我们可以简单的使用“$PS1=XXX…”这种格式对这个变量进行设置,从而达到将命令提示符进行改变的目的,但这种改变只是在内存中存在(系统实际上是运行在内存中,我理解为:在linux系统中,大量的文件构成了“剧本”,而运行于内存中的系统和程序就是播放在大银幕上的“电影”),当用户登出,这种改变就会消失,要让设定永远生效,前面也提到,需要将配置写入/etc/issue中,下次登录时,系统才会读取新的配置(剧本改了,电影也变了),像这种变量就是系统中自带的变量,它们被linux的编程人员写入到了系统文件中(后面会学习bash相关的配置文件的知识),当需要时,系统就会读取这些文件,从而生成一个个变量在内存中,来控制和规范系统的各种功能。

bash内建的环境变量:

PATH

SHELL

USER

UID

HOME

PWD

SHLVL

LANG

MAIL

HOSTNAME

HISTSIZE

— 这不是分隔符,这是变量,$_ 代表上一个命令里最后一个字符串

 

除了这些系统自带的变量,用户自己也能够定义变量,定义的方式很简单:

 

[root@Centos6 ~ 01:40:17]#aaa=bbb

[root@Centos6 ~ 01:50:47]#echo $aaa

bbb

我们对$aaa进行赋值,让它等于bbb,使用我们前面用过的echo命令,我们看到,它的值就是bbb。

在这个例子中,让$aaa=bbb显然是没什么用的,我们的目的是实现更多的功能:

1,、数据存储

[root@Centos6 ~ 01:50:56]#aaa=/etc/sysconfig/network-scripts/ifcfg-eth0

[root@Centos6 ~ 01:57:48]#cat $aaa

DEVICE=eth0

TYPE=Ethernet

UUID=3b1c360c-c451-42ef-9bb8-a3658877f100

ONBOOT=yes

NM_CONTROLLED=yes

BOOTPROTO=dhcp

HWADDR=00:0C:29:7F:06:C1

DEFROUTE=yes

PEERDNS=yes

PEERROUTES=yes

IPV4_FAILURE_FATAL=yes

IPV6INIT=no

NAME=”System eth0″

LAST_CONNECT=1522142921

用aaa3个字母,代替了那冗长的路径名

2、参与的运算

[root@Centos6 ~ 02:01:09]#b=20

[root@Centos6 ~ 02:01:27]#c=30

[root@Centos6 ~ 02:01:39]#aaa=$[b+c]

[root@Centos6 ~ 02:02:16]#echo $aaa

50

3、表示的数据范围。

 

除了输入内容对变量进行赋值,也可以用变量对变量进行赋值,当变量对变量赋值时,其作用原理类似于我们前面讲到的硬链接实现的机制,只是硬盘变成了内存,那么看下面的例子回忆一下:

[root@Centos6 ~ 02:02:19]#a=aaa 对a赋值aaa

[root@Centos6 ~ 02:11:20]#b=$a 对b赋值让它等于$a,注意,这里是让b等于变量a,必须加$

[root@Centos6 ~ 02:11:31]#a=bbb 改变a的值为bbb

[root@Centos6 ~ 02:11:38]#echo $a

bbb $a变成了bbb

[root@Centos6 ~ 02:11:44]#echo $b

aaa $b依然是$a原来的值aaa

变量还可以储存命令,输出时显示的是命令执行的结果

[root@Centos6 ~ 02:49:22]#a=cat /etc/issue 命令使用反引号引起来

[root@Centos6 ~ 02:55:07]#echo $a 对变量不加双引号,显示内容成一行

CentOS release 6.9 (Final) Kernel \r on an \m \d \n \t Please do not operate

[root@Centos6 ~ 02:55:16]#echo “$a” 加上双引号,按原文本格式显示

CentOS release 6.9 (Final)

Kernel \r on an \m

\d \n \t

Please do not operate

在这种赋值时,使用反引号和使用单引号效果是不同的,有兴趣的可以自己试试。

除了系统自带变量和用户自定义变量这种分类法,更加有意义的变量分类是:局部变量和环境变量。

局部变量和全局变量的区别在于其生效范围的不同,

局部变量只对当前的shell进程生效,而全局变量除了在当前的shell进程中生效,还可以传递给当前shell进程的子进程、子子进程…,注意:全局变量是不能反向传递的,即,不能有子进程传递给父进程。

****这里是老师使用的大量的试验来得出结论,时间紧任务重,本次笔记不能一一做试验复现,待以后时间充足的时候补充(下同)。

这里需要补充大量的概念:

*linux中常用的的shell类型为bash,当进入系统后,命令行出现,其实用户就已经处于一个bash的进程当中,而在这时继续输入bash命令,就会再打开一个bash进程,用户同样可以在这个进程中进行各种操作,但其实用户已经不在开始的进程当中了,后面输入bash开的进程,对于前一个bash进程而言就是子进程,而前一个bash进程就是它的父进程,这就是父进程和子进程的概念,类似的还有爷爷进程,子子进程,大概就是这么个意思。

*对于bash shell来说,当对变量进行赋值的时候,默认都是字符串,比如:i=100,并不是i=100这个数。而是i=1 0 0这三个字符组成的字符串,而且对bash shell来说是不支持浮点数的(小数),shell编程只是帮助完成对linux系统的控制的手段,并非一门功能完整的计算机语言。

*与脚本的命名类似,变量的命令也应该遵循见名知义的原则,命名时,可采用词首大写(大驼峰法)、除了首母以外的词首大写(小驼峰法)、单词间用下划线隔开等方法进行命名,同时应遵循不使用系统关键字(保留字)进行命名的原则(如if,for等),避免系统识别时出现混乱。

*脚本在执行的过程中是开了一个子bash

*当变量和字符串连在一起执行时就不能写$varname这种格式了,需要加大括号{},${varname}

一条生成随机色的命令,前面的变量是生成随机数并对7取余数,然后加上31,得出颜色码31-37。颜色相关可参阅前面的笔记:

[root@Centos6 ~/bin 03:34:11]#color=$[RANDOM%7+31];echo -e “\e[1;${color}mHello\e[0m”

Hello

*单引号‘’强引用作用依然有效,‘$var’显示的是$var字符串本身。

***

*补充命令

export 声明定义的变量为全局变量,可以在定义时声明,也可以在变量定义后声明,类似还有declare命令:

export name=VALUE

export name

declare -x name=VALUE

 

显示所有环境变量:

env

printenv

export

declare 用于声明和显示已存在的shell变量。当不提供变量名参数时显示所有shell变量。declare命令若不带任何参数选项,则会显示所有shell变量及其值。

r:将变量设置为只读;

x:指定的变量会成为环境变量,可供shell以外的程序来使用;

set显示已定义的所有变量:

unset name 可用于删除变量

pstree 查看进程树

 

-p选线:显示pid(进程id)

readonly 将变量声明为只读变量(常量),只读变量在当前bash进程结束时才会消失。

-p 显示系统中的常量

*变量在不用时应当及时删除,前面说过变量的赋值方法类似硬链接,其储存方式当然也是类似,如果一个变量一直不删除,系统内存中就会长期被占用一个数据空间,对家用pc机不算什么,重启就会消失,对于长时间运行的服务器日积月累是个巨大的负担。

*$$ 显示当前bash进程的进程id,$PPID显示父进程的进程id

除此之外还可以分为:

本地变量:生效范围为当前shell进程中某代码片断,通常指函数

位置变量:$1, $2, …来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数,$1表示脚本后跟的参数中左起第一个,依次往后是$2、$3……。

特殊变量:

$?:显示上一个命令执行后的返回值,0为命令执行成功,其他数值为执行失败

$0:当前脚本的名称(绝对路径完整路径名,可用basename取出文件名)

如果是通过软连接调用的脚本,$0显示的是软连接名,到以后学习了判断之后,可以对同一个脚本建立多个软链接,当使用不同的软连接调用脚本时可实现不同的功能。

$*:将所有参数传递给脚本(当使用双引号引起来时,所有参数将合并为一个参数,不使用双引号时与$@相同)

$@:将所有参数传递给脚本(每个参数作为独立参数)

$#:传递给脚本的参数个数

set — 清空所有位置变量

bash中()和{}的区别

()在小括号中执行的操作不会影响当前的bash进程或环境,可以理解为在小括号中执行操作时,如果有操作会改变当前bash的环境,系统就会开一个子bash,在子bash中执行操作

[root@Centos6 ~/bin 03:33:49]#x=1;echo “pid=$$”;(echo “subpid=$$”;echo “subx=$x”;x=2;echo “subx2=$x”);echo x=$x

pid=18602 当前进程号

subpid=18602 虽然有小括号,但执行打印命令并未开启子进程

subx=1 变量值也未发生变化

subx2=2 赋值后变量值发生了变化

x=1 括号结束,子bash结束,当前进程中的x值依然为1

小括号的这个特性可以用在某些需要临时改变某些环境(比如改变当前所在文件夹,改变系统的某个默认设置)执行命令的情况下,当命令执行结束,操作环境又回到当前的bash环境,简化操作。

{}在大括号中执行的操作只影响当前的bash进程或环境,当在脚本中,如果某些命令想捆绑着一起执行然后exit,就必须用大括号,因为刚才解释了小括号的特性,大家应该就明白,如果使用小括号很可能只是退出了子shell,脚本还在继续执行。

shift命令 会拿掉位置变量的$1,将后面的参数向前位移一位,即原来的$2会变成现在的$1,也支持一次拿掉多个。这项技术以后学习了循环之后有用。

脚本练习题

1、编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小

#!/bin/bash

#

#********************************************************************

#Author: feng16

#QQ:

#Date: 2018-04-09

#FileName: systeminfo.sh

#URL: /user/fengshun

#Description: The test script

#Copyright (C): 2018 All rights reserved

#********************************************************************

echo “My hostname is hostname

echo The IPv4 is ifconfig eth0 | egrep -o "\<((2[0-4][0-9]|25[0-5]|1[0-9]{1,2}|[1-9][0-9]|[0-9])\.){3}(2[0-

4][0-9]|25[0-5]|1[0-9]{1,2}|[1-9][0-9]|[0-9])\>"|head -1

echo “The cat /etc/redhat-release

echo “Linux kernel version is uname -r

echo “lscpu | grep "Model name" | tr -s " "

echo “cat /proc/meminfo | head -1|tr -s " "

echo “Disk size is lsblk | grep "sda\>"|tr -s " "|cut -d" " -f4

运行结果:

[root@Centos6 ~/bin 04:23:32]#16_systeminfo.sh

My hostname is Centos6.9.magedu30

The IPv4 is 192.168.65.142

The CentOS release 6.9 (Final)

Linux kernel version is 2.6.32-696.el6.x86_64

Model name: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz

MemTotal: 1004112 kB

Disk size is 200G

2、编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY-mm-dd中

脚本头省略

cp -aR /etc/ /root/etcdate "+%F"&&echo “copy finished”||echo “something is wrong”

执行结果:

[root@Centos6 ~/bin 04:26:47]#16_backup.sh

copy finished

[root@Centos6 ~/bin 04:28:04]#ls -a /root/etc2018-04-10

. fprintd.conf makedev.d rdma

.. fstab man.config readahead.conf

2der2e gai.conf maven reader.conf

abrt gconf mime.types reader.conf.d

acpi gcrypt mke2fs.conf redhat-lsb

adjtime gdm modprobe.d redhat-release

……省略……

3、编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值

脚本头省略

DISK=df|grep "/sd"|tr -s " " "%"|cut -d% -f5|sort -nr|head -1

[ “$DISK” -ge 80 ]&&wall Disk will be full||echo “Sufficient disk space”

执行结果:

[root@Centos6 ~/bin 04:32:47]#16_disk.sh

Sufficient disk space

4、编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序 以前做过,跳过 netstat -nr

算术运算

bash中的算术运算:

帮助信息:help let

+, -, *, /, %取模(取余), **(乘方)

实现算术运算的几种方法:

(1) let var=算术表达式

(2) var=$[算术表达式]

(3) var=$((算术表达式))

(4) var=$(expr arg1 arg2 arg3 …)

(5) declare –i var = 数值

(6) echo ‘算术表达式’ | bc

乘法符号有些场景中需要转义,如*

bash有内建的随机数生成器:$RANDOM(0-32767)

echo $[$RANDOM%50] :0-49之间随机数(就是上面随机色命令的实现方法)

赋值

增强型赋值:

+= ,-= ,*= ,/= ,%=

let varOPERvalue

例如: let count+=3 自加3后的值重新赋给自己

自增,自减:

let var+=1

let var++

let var-=1

let var–

aa=10

$((aa++))显示值10,然后将值11赋给aa

$((++aa))先将值11赋给aa,显示11

+=1相当于++,不同的是+=后面还可以跟其他数字

练习题,下面的练习题因为学习了后面的知识,全部将功能进行了加强,选择性浏览,看完后面再回头看前面

1、编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和,老师额外要求脚本实现任意两个用户的ID之和。

本来是一道很简单的编程,多了一个要求后变得不简单了,要实现功能,除了需要使用以前学过的文本处理命令从passwd文件中抽取需要的uid计算出结果,还需要考虑

1、用户输入参数没有

2、用户输入的参数是否为有效参数

编写脚本如下:

#!/bin/bash

[ $# -eq 2 ]||{ echo “You must enter 2 numbers”; exit; } 判断参数是否为两个

[[ “$1” =~ ^[[:digit:]]+$ ]]&&[[ “$2” =~ ^[[:digit:]]+$ ]]||{ echo “You must enter numbers”; exit; }判断是否为纯数字

maxnum=cat /etc/passwd|wc -l 计算系统中有多少个用户

[ “$1” -le “$maxnum” ]&&[ “$2” -le “$maxnum” ]||{ echo “Not so many users”; exit; } 比较用户参数是否超出总用户

UID1=cat /etc/passwd|head -$1|tail -1|cut -d: -f3 取出用户1的uid

UID2=cat /etc/passwd|head -$2|tail -1|cut -d: -f3 取出用户2的uid

SUM2=$[UID1+UID2] 计算出uid和

echo “As the sum of the UID1 and UID2 is “$SUM2″” 输出到终端

运行结果:

合法参数

[root@Centos6 ~/bin 06:46:04]#16_sumid.sh 10 20

As the sum of the UID1 and UID2 is 180

非法参数一

[root@Centos6 ~/bin 06:50:22]#16_sumid.sh 10 200

Not so many users

非法参数二

[root@Centos6 ~/bin 06:50:59]#16_sumid.sh 10 2ww

You must enter numbers

2、编写脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和

**需要判断是不是两个参数**需要判断文件的存在性**需要计算空白行数结果

编写脚本如下:

[ $# -eq 2 ]||{ echo “You should provide two file name”; exit; }

[ -e $1 ]&&[ -e $2 ]||{ echo “Please check the file exists”; exit; }

Linenum1=grep ^[[:space:]]*$ $1 | wc -l

Linenum2=grep ^[[:space:]]*$ $2 | wc -l

sum=$[ Linenum1+Linenum2 ]

echo “Sum of the number of blank lines is $sum”

执行结果

正确参数

[root@Centos6 ~/bin 07:12:05]#16_sumspace.sh /root/.bash_history /root/.bash_logout

Sum of the number of blank lines is 24

错误路径

[root@Centos6 ~/bin 07:12:12]#16_sumspace.sh /root/.bash_history /root/.ff

Please check the file exists

参数不够

[root@Centos6 ~/bin 07:12:18]#16_sumspace.sh /root/.bash_history

You should provide two file name

发现grep命令自带行数统计,改进脚本如下:

[ $# -eq 2 ]||{ echo “You should provide two file name”; exit; }

[ -e $1 ]&&[ -e $2 ]||{ echo “Please check the file exists”; exit; }

Linenum1=grep -c ^[[:space:]]*$ $1

Linenum2=grep -c ^[[:space:]]*$ $2

sum=$[ Linenum1+Linenum2 ]

echo “Sum of the number of blank lines is $sum”

 

3、编写脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件

[root@Centos6 ~/bin 07:20:13]#cat 16_sumfile.sh

num1=ls -A /etc | wc -l

num2=ls -A /var | wc -l

num3=ls -A /usr | wc -l

sum=$[ num1+num2+num3 ]

echo “The calculation is $sum”

运行结果

[root@Centos6 ~/bin 07:20:32]#16_sumfile.sh

The calculation is 298

 

逻辑运算

注意,逻辑运算中的1和0代表的意义与上个命令的退出状态中(存储在变量$?中)的“0”是不一样的,这里的1代表真 0代表假

真 假

true false

1 0

与:

1 与 1 = 1

1 与 0 = 0

0 与 1 = 0

0 与 0 = 0

或:

1 或 1 = 1

1 或 0 = 1

0 或 1 = 1

0 或 0 = 0

非:!

! 1 = 0

! 0 = 1

短路运算

 

短路与&&

第一个为0,结果必定为0

第一个为1,第二个必须要参与运算

  • && 代表条件性的 AND THEN

cmd1&&cmd2 参照前面的逻辑运算,当是与(&)关系时,如果cmd1的执行结果为假,那么结果必然是假,cmd2没有必要执行,根据这个逻辑,有了短路与和短路或,

cmd1&&cmd2 如果cmd1为假,则不执行cmd2

 

短路或||

第一个为1,结果必定为1

第一个为0,第二个必须要参与运算

  • || 代表条件性的 OR ELSE

cmd1||cmd2 如果cmd1为真,则不执行cmd2(参考短路与的由来)

借助短路与和短路或的这些特性,根据退出状态而定,命令可以有条件地运行,在脚本中实现简单的逻辑判断。

 

异或:^

异或的两个值,相同为假,不同为真

 

条件测试

判断某需求是否满足,需要由测试机制来实现

专用的测试表达式需要由测试命令辅助完成测试过程

评估布尔声明,以便用在条件性执行中

  • 若真,则返回0
  • 若假,则返回1

测试命令 test命令:

  • test EXPRESSION 长格式:

test “$A” == “$B” && echo “Strings are equal”

test “$A” -eq “$B” && echo “Integers are equal”

  • [ EXPRESSION ] 常用,因为系统中自带脚本是这种写法,且比上一种方法更一目了然

[ “$A” == “$B” ] && echo “Strings are equal”

[ “$A” -eq “$B” ] && echo “Integers are equal”

  • [[ EXPRESSION ]] 使用正则表达式进行匹配时使用

注意:EXPRESSION前后必须有空白字符

 

bash的数值测试

-v VAR

变量VAR是否设置

当使用-v来判断变量是否已设置时,有一个缺点,就是变量当变量被赋了一个“空”值,-v选项依然会认为这个变量已赋值,但显然空值和没赋值是一样的效果,在用于脚本中时可能会造成不可预知的后果,所以一般使用下面这种方法判断变量是否有值:

[root@Centos6 ~/bin 10:20:27]#aaa=””

[root@Centos6 ~/bin 10:32:27]#[ -v $aaa ]

[root@Centos6 ~/bin 10:32:30]#echo $? aaa的值明明是空的,返回值却为0(真),这不是我们想要的。

0

通过字符串测试来判断变量是否为空

[root@Centos6 ~/bin 10:32:32]#[ “$aaa”xx == “xx” ]

[root@Centos6 ~/bin 10:35:10]#echo $?

0

[root@Centos6 ~/bin 10:35:14]#aaa=xxx

[root@Centos6 ~/bin 10:35:28]#[ “$aaa”xx == “xx” ]

[root@Centos6 ~/bin 10:35:31]#echo $?

1

数值测试:

-gt 是否大于 记忆点,e表示等于 ,g表示大于 ,l表示小于 ,剩下q t就好记了。

-ge 是否大于等于

-eq 是否等于

-ne 是否不等于

-lt 是否小于

-le 是否小于等于

bash的字符串测试

字符串测试:

== 是否等于

!= 是否不等于

=~ 左侧字符串是否能够被右侧的PATTERN所匹配

注意: 此表达式一般用于[[ ]]中;扩展的正则表达式

> ascii码是否大于ascii码 不常用

< 是否小于 不常用

 

-z “STRING“ 字符串是否为空,空为真,不空为假

-n “STRING“ 字符串是否不空,不空为真,空为假

注意:用于字符串比较时的用到的操作数都应该使用引号

当使用判断功能时,和运算是不同的,在中括号中各个字符串和判断符前后都要加上空格。

Bash的文件测试

存在性测试

-a FILE:同-e

-e FILE: 文件存在性测试,存在为真,否则为假

存在性及类别测试

-b FILE:是否存在且为块设备文件

-c FILE:是否存在且为字符设备文件

-d FILE:是否存在且为目录文件

-f FILE:是否存在且为普通文件

-h FILE 或 -L FILE:存在且为符号链接文件

-p FILE:是否存在且为命名管道文件

-S FILE:是否存在且为套接字文件

Bash的文件权限测试

文件权限测试:

-r FILE:是否存在且可读

-w FILE: 是否存在且可写

-x FILE: 是否存在且可执行

文件特殊权限测试:

-u FILE:是否存在且拥有suid权限

-g FILE:是否存在且拥有sgid权限

-k FILE:是否存在且拥有sticky权限

Bash的文件属性测试

文件大小测试:

-s FILE: 是否存在且非空

文件是否打开:

-t fd: fd 文件描述符是否在某终端已经打开

-N FILE:文件自从上一次被读取之后是否被修改过

-O FILE:当前有效用户是否为文件属主

-G FILE:当前有效用户是否为文件属组

双目测试:

FILE1 -ef FILE2: FILE1是否是FILE2的硬链接

FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)

FILE1 -ot FILE2: FILE1是否旧于FILE2

在大多数时候,我们想要判断的条件并非一个,bash也提供了将条件组合在一起进行判断的办法:

第一种方式:

COMMAND1 && COMMAND2 并且

COMMAND1 || COMMAND2 或者

! COMMAND 非

如:[[ -r FILE ]] && [[ -w FILE ]]

第二种方式:

[ EXPRESSION1 -a EXPRESSION2 ] 并且

[ EXPRESSION1 -o EXPRESSION2 ] 或者

[ ! EXPRESSION ] 使用非“!”时,写在类别选项的前面用空格隔开[ ! -r file]

必须使用测试命令进行

练习:

1、编写脚本/bin/per.sh,判断当前用户对指定参数文件,是否不可读并且不可写

要求对用户输入的参数文件进行处理,必须首先确定用户是否输入的参数,或者参数文件是否存在,并给出提示

判断要求为不可读且不可写,除了使用非“!”以外,也可以认为,文件能读或者能写都不符合条件,写出脚本如下:

脚本头部依然省略

[ -n “$1” ]||{ echo “You must enter a filename as a parameter.”; exit; } 对用户是否输入了参数进行判断

[ -e “$1” ]||{ echo “This file can not be find!”; exit; } 对用户输入的文件进行存在性判断

[ -r $1 -o -w $1 ]&&echo “This file can read or write”||echo “This file can not read or write”

*在测试该脚本的过程中发现,当使用完全切换时,普通用户是无法使用该脚本的,因为脚本都在root的家目录中,普通用户进不去,而使用不完全切换时(root停留在/root/bin下),虽然不能直接运行脚本,但可以通过bash来使用脚本。

当文件能读或者能写时,不符合题意,使用或判断组合测试条件,为真时证明文件能读或者能写,为假时证明既不能读也不能写。

运行结果:

[root@Centos6 ~/bin 09:29:34]#16_per.sh 未输入文件名

You must enter a filename as a parameter.

[root@Centos6 ~/bin 09:29:41]#16_per.sh f1 无效的文件名

This file can not be find!

[root@Centos6 ~/bin 09:33:17]#16_per.sh /data/issue.out 有效的文件名

This file can read or write

2、编写脚本/root/bin/excute.sh ,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限,否则提示用户非脚本文件

给文件加执行权限简单,但同样的,需要考虑到用户是否输入了参数以及参数是否有效的问题,编写脚本如下:

[ -z $1 ]&&{ echo “You must enter a file name.”; exit; } 判断用户是否输入了文件名

[ -a $1 ]||{ echo “This file can not be find.”; exit; } 判断文件的存在性

[ -f $1 ]||{ echo “This is not a normal file.”; exit; } 判断文件是否为普通文件

[[ $1 =~ .+\.sh ]]&&chmod +x $1||echo “This is not a script file.” 前面的判断都通过之后,判断文件是否有sh后缀

在上面的脚本中,前面的几条判断代码其实是可以通过组合判断的方法进行合并,但为了让提示信息更加明确,在还没有学习到更好的办法之前,暂时通过这种方法实现。

运行结果:

[root@Centos6 ~/bin 09:52:16]#16_excute.sh

You must enter a file name.

[root@Centos6 ~/bin 09:52:27]#16_excute.sh f1

This file can not be find.

[root@Centos6 ~/bin 09:55:53]#16_excute.sh /dev/dvd

This is not a normal file.

[root@Centos6 ~/bin 09:57:08]#16_excute.sh testfile

This is not a script file.

 

3、编写脚本/root/bin/nologin.sh和login.sh,实现禁止和充许普通用户登录系统

禁止用户登录只需要在/etc目录下建立一个nologin文件即可,那么在建立或者删除个文件之前,必须对这个文件是否存在进行判断。

nologin.sh脚本

[ -a /etc/nologin ]&&echo “Ordinary users are not allowed to login.”||touch /etc/nologin

运行结果:

[root@Centos6 ~/bin 10:10:19]#bash -x 16_nologin.sh 这里使用的bash -x的调试功能,注意,调试功能

+ ‘[‘ -a /etc/nologin ‘]’ 只是会显示程序的运行过程,依然是会对系统进行

+ touch /etc/nologin 实际操作的,在实际生产过程中,调试命令应在测

[root@Centos6 ~/bin 10:10:32]#bash -x 16_nologin.sh 试环境中进行而不是实机上。

+ ‘[‘ -a /etc/nologin ‘]’

+ echo ‘Ordinary users are not allowed to login.’

Ordinary users are not allowed to login.

在nologin文件中可以使用重定向技术输入一句文本,当普通用户登录时可以对其进行通知,告知不能登录的原因,我很懒就不试了。

login.sh脚本

当nolongin存在时,就删除它,否则证明普通用户已经被允许登录,打印一段提示即可

[ -a /etc/nologin ]&&rm -rf /etc/nologin||echo “Ordinary users are allowed to login.”

运行结果:

 

[root@Centos6 ~/bin 10:17:13]#16_login.sh

[root@Centos6 ~/bin 10:20:23]#16_login.sh

Ordinary users are allowed to login.

read 该命令用于从标准输入中读取一行,并把输入行的每个字段的值指定给shell变量。

read 从标准输入中读取值,给每个单词分配一个变量,当变量数比单词数少时,所有剩余单词都被分配给最后一个变量

read x y z <f1 虽然支持这种格式,但只能识别同一行用空格隔开的字符串

read x y z <<<“i j k”

-p 指定要显示的提示,可用于脚本中提示用户输入参数

-s 静默输入,一般用于密码

-n N 指定输入的字符长度N

-d ‘字符’ 输入结束符,当命令读到结束符时将结束符前面的内容读入

-t N TIMEOUT为N秒,等待时间

 

read -p “Enter a filename: “ FILE

bash如何展开命令行

bash按下面的顺序展开命令

把命令行分成单个命令词

》》展开别名

》》展开大括号的声明({})

》》展开波浪符声明(~)

》》命令替换$() 和

》》再次把命令行分成命令词

》》展开文件通配(*、?、[abc]等等)

》》准备I/0重导向(<、>)

》》运行命令

bash的配置文件

当linux系统启动时,会读取磁盘上存放的配置文件中的信息,对用户的操作环境进行一系列的配置,通常情况下,我们的默认交互shell类型就是bash,当用户登录到系统时,如果是文字界面,那么会出现一个命令提示符,这个命令提示符就是由bash启动的,用做与用户进行交互的“接口”,bash也有一系列的配置文件来设定其与用户交互时的环境,我们可以通过改变这些文件来让自己与系统之间的交互变得更加顺畅。

和变量的分类类似,或者说,有些变量本身就是读取这些配置文件来生成的,按生效范围划分,存在两类:

全局配置:

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

个人配置:

~/.bash_profile

~/.bashrc

shell有两种登录方式,交互式登录和非交互式登录

交互式登录:

(1)直接通过终端输入账号密码登录

(2)使用“su – UserName” 切换的用户

执行顺序:/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile –> ~/.bashrc –> /etc/bashrc

非交互式登录:

(1)su UserName

(2)图形界面下打开的终端

(3)执行脚本

(4)任何其它的bash实例

执行顺序: ~/.bashrc –> /etc/bashrc –> /etc/profile.d/*.sh

/etc/profile.d/*.sh 这个位置的配置文件我们曾经在前面使用过,可以将自定义的一些配置放在profile.d/下,并且以。sh为后缀,这样可以避免去修改系统自带的配置文件,减少误操作。我们可以看到上面提到的几个配置文件的文件名有profile或者bashrc这样的字符串,通常来说,profile类的配置文件中存放的是环境变量,所以一般我们往这里放一些环境相关的个性配置。

按功能划分,存在两类:

profile类和bashrc类

profile类:为交互式登录的shell提供配置

全局:/etc/profile, /etc/profile.d/*.sh

个人:~/.bash_profile

功用:

(1) 用于定义环境变量

(2) 运行命令或脚本

bashrc类:为非交互式和交互式登录的shell提供配置

全局:/etc/bashrc

个人:~/.bashrc

功用:

(1) 定义命令别名和函数

(2) 定义本地变量

在前面的学习中就提到过,要修改系统的某项配置,在内存中修改后,还需要将配置信息写到对应的配置文件中,才能保证在下次登录时配置依然有效,或者是直接写入文件中,通过source或者“.”来让配置生效,否则要让直接写入到配置文件中的配置生效,需要重新启动shell,这里重新描述一遍,是因为前面我们学习了脚本的内容,运行脚本,也可以通过bash接文件名的方式运行,而配置文件实际上也类似一个脚本,它们都可以互相用对方的运行方式运行,但是意义是截然不同的,当使用“.”或source来运行配置文件时,我们通常会说叫载入配置文件,其读取的配置,是在当前的bash进程中生效的,如果用这种方法运行脚本,很可能会造成系统混乱,而用运行脚本的方法运行配置文件,前面说过,运行脚本的时候实际上是开了一个子进程,运行的配置载入到了子进程中,进程结束,子进程中的配置就都消失了,起不到载入配置的作用。

 

Bash 退出任务

在家目录下有一个配置文件~/.bash_logout文件,当用户将希望bash在退出前进行的操作写入这个文件中后,这个文件会在退出登录shell时运行,起到类似windows关机任务的作用:

  • 创建自动备份
  • 清除临时文件

特殊变量$-:

变量$-中存放的是当前bash中的一些重要的配置信息,使用单个字母组成的字符串表示系统中的某些功能是否打开,可以通过set +和set -来关闭或开启某些功能,要注意的是,+号是关闭,-是开启,和正常人的思维习惯相反:

[root@Centos6 ~ 12:22:34]#echo $-

himBH

h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭

i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的。

m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等。

B:braceexpand,大括号扩展

H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令

1、让所有用户的PATH环境变量的值多出一个路径,例如:/usr/local/apache/bin

对所有用户都生效,那么需要配置全局配置,全局配置的的位置在/etc/下,如果打开/etc/profile,会发现在文件开头的注释中有这样一段话:

# It’s NOT a good idea to change this file unless you know what you

# are doing. It’s much better to create a custom.sh shell script in

# /etc/profile.d/ to make custom changes to your environment, as this

# will prevent the need for merging in future updates.

英语学渣,大概翻译下:改这个文件不是个好主意,除非你很NB,最好是在/etc/profile.d/这个文件夹下创建一个.sh结尾的自定义文件(是这个意思么???)来放你的环境配置等等等……

那么创建/etc/profile.d/env.sh文件写入:

PATH=”/usr/local/apache/bin:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/r

oot/bin”

即复制原有的$PATH内容,将需要加入的路径加入到开头,并以冒号作为分割符

[root@Centos6 /etc/profile.d 01:47:48]#echo $PATH

/usr/local/apache/bin:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

2、用户root登录时,将命令指示符变成红色,并自动启用如下别名:rm=‘rm –i’

cdnet=‘cd /etc/sysconfig/network-scripts/’

editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’

editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eno16777736 或 ifcfg-ens33 ’ (如果系统是CentOS7)

指定为root用户定制,配置填入用户家目录下的配置文件中:

别名填入~/.bashrc文件中

alias cdnet=’cd /etc/sysconfig/network-scripts/’

alias editnet=’vim /etc/sysconfig/network-scripts/ifcfg-eth0′ CentOS7中只有最后网卡名不同

命令提示符的配置填入~/.bash_profile

PS1=’\[\e[1;31m\][\u@\h \w \T]\$\[\e[0m\]’ 注意为单引号

3、任意用户登录系统时,显示红色字体的警示提醒信息“Hi,dangerous!”

任意用户,配置环境变量,在/etc下有一个motd文件,填入下面的信息即可

^[[33m=====================================^[[0m

^[[1;31mHi,dangerous!^[[0m

^[[1;31mHi,dangerous!^[[0m

^[[34m=====================================^[[0m

这里要注意的是颜色控制符,在echo命令中,或者PS1变量中我们使用的是\e[作为颜色控制符的开头,但在文本中,这种写法是不能识别的,要用“ctrl+v+[”,输入一个显示为“^[”的符号来代替\e,并不是^和[符号,

4、编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等

首先要判断用户是否输入了合法的文件名,我认为脚本文件应以.sh结尾:

[[ $1 =~ .+\.sh$ ]]||{ echo “You should enter a script name like *.sh.”; exit; } 判断脚本名是否合法

[ -e $1 ]&&{ echo “This script is allready exists , please enter another name”; exit; } 判断脚本名是否存在

cat > $1 << eof 利用多行重定向制作表头

#!/bin/bash

#

#********************************************************************

#Author: feng16

#QQ:

#Date: date "+%F"

#FileName: $1

#URL: /user/fengshun

#Description: The test script

#Copyright (C): 2018 All rights reserved

#********************************************************************

 

eof

chmod +x $1 为新创建的脚本文件加执行权限

vim $1 + 用vim将脚本文件打开,并定位到最新的一行

5、编写用户的环境初始化脚本reset.sh,包括别名,登录提示符,vim的设置,环境变量等

这个……等学了更多的命令再慢慢做

文件的查找与压缩

locate 通过查询系统上预建的文件索引数据库来找到符合条件的文件所在的路径

数据库位置:/var/lib/mlocate/mlocate.db。

数据库的建立是在系统较为空闲时自动进行的(周期性任务),但管理员可以通过命令updatedb手动立即更新数据库。即使是手动更新,依然建议在系统空闲时进行,因为索引的构建过程会搜索整个根文件系统,会极大的消耗系统资源。

工作特点:

  • 查找速度快
  • 模糊查找
  • 非实时查找
  • 搜索的是文件的全路径,不仅仅是文件名
  • 可能只搜索用户具备读取和执行权限的目录

locate KEYWORD

当locate直接搜索时,默认是模糊匹配的,只要含有符合要求的字符串即匹配。

常用选项:

-i 不区分大小写的搜索

-n N 只列举前N个匹配项目

-r 使用正则表达式

由于locate的搜索原理,在使用时,一般用于搜索一些长时间不会变动的文件,以获取更快的搜索速度,并节约系统资源。

find find命令是一个功能强大的实时搜索工具,和locate不同,除了可以实时搜索不受数据库是否更新的限制,find命令还可以对匹配出来的文件进行一些处理动作。

其搜索也有一定的局限性,如果用户对某个文件夹没有执行权限,那么通过find命令无法找到该文件夹下的文件。

工作特点:

  • 查找速度慢
  • 精确查找
  • 实时查找
  • 可能只搜索用户具备读取和执行权限的目录

语法:

find [option] [路径] [条件] [处理动作]

当不输入路径时,默认搜索用户当前所在文件夹

当不输入处理动作时,默认打印搜索结果到标准输出

当不输入查找条件时,默认为指定路径下的所有文件

 

指定搜索层级

-maxdepth level 最大搜索目录深度,指定目录为第1级

-mindepth level 最小搜索目录深度

两个条件可组合使用,表示从多少层到多少层

根据文件名和inode查找:

-name “文件名称”:支持使用glob “*, ?, [], [^]”,在使用-name进行匹配时,文件名必须是basename基名,如果想带dirname,则需要使用-path

-iname “文件名称”:不区分字母大小写

-inum n 按inode号查找

-samefile name 相同inode号的文件 就是查找硬链接

-links n 链接数为n的文件

-path 查找路径名匹配所给字串的所有文件,字串内可用通配符*、?、[ ],以完整的路径名来进行匹配,且匹配时不支持路径名的最后带“/”

-ipath 忽略大小写的-path

-regex “PATTERN”:以PATTERN匹配整个文件路径字符串,而不仅仅是文件名称,使用正则表达式,再强调一遍注意是匹配整个文件路径。

根据属主、属组查找:

-user USERNAME:查找属主为指定用户(UID)的文件

-group GRPNAME: 查找属组为指定组(GID)的文件

-uid UserID:查找属主为指定的UID号的文件

-gid GroupID:查找属组为指定的GID号的文件

-nouser:查找没有属主的文件 如果某个用户被删除了,就会产生没有主的文件或目录,就可以使用这条命令来寻找。

-nogroup:查找没有属组的文件

根据文件类型查找:

-type 文件类型:

  • f: 普通文件
  • d: 目录文件
  • l: 符号链接文件
  • s:套接字文件
  • b: 块设备文件
  • c: 字符设备文件
  • p: 管道文件

空文件或目录

-empty

find /app -type d -empty 在/app下寻找空目录

find命令也支持将条件组合起来进行查找

组合条件:

与:-a

或:-o

非:-not, !

德·摩根定律:

(非 A) 或 (非 B) = 非(A 且 B)

(非 A) 且 (非 B) = 非(A 或 B)

find支持小括号,但使用时,需要加\转义

通过交并集的知识可以很好的理解这一定律,可以简单的总结为,当合并括号或展开括号时,“或”要换成“且”,“且”要换成“或”。

处理动作

-print:默认的处理动作,显示至屏幕

-ls:类似于对查找到的文件执行“ls -l”命令

-delete:删除查找到的文件 危险命令,不提示就删除,不建议使用,最好是用管道传给其他命令处理

-fls file:查找到的所有文件的长格式信息保存至指定文件中相当于 -ls > file

-ok COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令,对于

每个文件执行命令之前,都会交互式要求用户确认

-exec COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令,不进行提示。

{}: 用于引用查找到的文件名称自身,类似后向引用的用法。

find /mnt -name “f*” -exec mv {} {}.bak \; 实现将查找到的文件进行批量改名。

find传递查找到的文件至后面指定的命令时,查找到所有符合条件的文件一次性传递给后面的命令

 

find -name snow.png 在用户当前所在的目录下搜索指定文件,精确匹配文件名,并显示在终端

find -iname snow.png 同上,但不区分文件名的大小写

find / -name “*.txt” 从/开始搜索以.txt为后缀的文件

find /var –name “*log*” 在/var文件夹下搜索含有log这样字符串的文件或文件夹

find -user joe -group joe 搜索属主为joe且属组为joe的文件

find -user joe -not -group joe 搜索属主为joe且属组不为joe的文件

find -user joe -o -user jane 搜索属主为joe或者属主为jane的文件

find -not \( -user joe -o -user jane \) 搜索属主既不是joe也不是jane的文件

find / -user joe -o -uid 500 搜索属主是joe或者uid为500的文件

在搜索时,可能我们已经知道某些目录下并没有我们需要的文件,find命令也提供了将这些目录排除掉的功能,在输入了查找的一级目录后:

输入-path…………-prune -o组合,中间输入匹配条件,满足条件的目录将不进行匹配(命令字面意思表示满足匹配条件的目录都“剪掉”),如果要匹配多个目录,只能多次输入-path来进行匹配,并且用括号将多个-path扩起来,以 -o 连接。

示例:

查找/etc/下,除/etc/sane.d目录的其它所有.conf后缀的文件

find /etc -path ‘/etc/sane.d’ –prune -o -name “*.conf”

查找/etc/下,除/etc/sane.d和/etc/fonts两个目录的所有.conf后缀的文件

find /etc \(–path ‘/etc/sane.d’ –o –path ’/etc/fonts’ \) -prune –o -name “*.conf”

根据文件大小来查找:

-size [+|-]#UNIT 使用-size时要注意,在匹配文件大小的时候,其实精确匹配是没有太大的意义的,所以设计者设定的匹配条件进行的是区间匹配:

常用单位:k, M, G,c(byte)

#UNIT: (#-1, #]

-#UNIT:[0,#-1]

+#UNIT:(#,∞)

以匹配6k为例:

-6k 0k(含)——5k(含)

6k 5k(不含)——6k(含)

+6k 6k(不含)——∞

在使用-size匹配文件时应注意上面的特点。

根据时间戳:

以“天”为单位;同样要注意,以时间戳为条件匹配时,依然存在区间的问题,

-atime [+|-]#,

#: [#,#+1)

+#: [#+1,∞]

-#: [0,#)

-mtime

-ctime

以“分钟”为单位:

-amin

-mmin

-cmin

根据权限查找:

-perm [/|-]MODE

MODE: 精确权限匹配

/MODE:任何一类(u,g,o)对象的权限中只要能一位匹配即可,或关系,+从centos7开始淘汰

-MODE:每一类对象都必须同时拥有指定权限,与关系,当使用这种匹配条件时,命令关心的是八进制值转换成二进制后,对应的权限位的权限,不对应的权限位,命令不去做判断,在使用“非”判断时要注意这一特性。

xargs命令,参数替换

由于很多命令不支持管道|来传递参数,而日常工作中有这个需要;同时,在linux中,命令能够处理的参数的个数是有限制的,比如一次删除大量的小文件,直接删除会提示你参数过长,所以就有了xargs命令,xargs能将参数的个数进行分割,再传给后面的命令进行处理。

xargs用于产生某个命令的参数,xargs 可以读入 stdin 的数据,并且以空格符或回车符将 stdin 的数据分隔成为arguments

注意:文件名或者是其他意义的名词内含有空格符的情况

有些命令不能接受过多参数,比如find,命令执行可能会失败,xargs可以解决

例如:find /sbin -perm +700 |ls -l 无法输出find的查找结果,只能输出ls -l的结果,必须写作

find /sbin -perm +700 |xargs ls -l

当然find也自带一个长格式输出:find /sbin -perm +700 -ls

find和xargs格式:find | xargs COMMAND

xargs的功能不仅仅是这么一点,以后补充

find命令练习

1、查找/var目录下属主为root,且属组为mail的所有文件

[root@Centos6 ~ 10:52:56]#find /var -user root -group mail -a ! -type d

/var/spool/mail/root

2、查找/var目录下不属于root、lp、gdm的所有文件

[root@Centos6 ~ 10:53:14]#find /var -not \( -user root -o -user lp -o -user gdm \) -a ! -type d -ls

3、查找/var目录下最近一周内其内容修改过,同时属主不为root,也不是postfix的文件

[root@Centos6 ~ 09:25:08]#find /var -mtime -7 -a -not \( -user root -o -user postfix \) -ls

657645 4 -rw-rw—- 1 xixi mail 1154 Apr 12 21:23 /var/spool/mail/xixi

657615 4 -rw-rw—- 1 fengshun16 mail 597 Apr 12 21:24 /var/spool/mail/fengshun16

4、查找当前系统上没有属主或属组,且最近一个周内曾被访问过的文件

[root@Centos6 ~ 09:30:27]#find / \( -nouser -o -nogroup \) -a -atime -7 -ls ????

5、查找/etc目录下大于1M且类型为普通文件的所有文件

[root@Centos6 ~ 09:31:12]#find /etc -type f -size +1M -ls

1974397 8280 -rw-r–r– 1 root root 8477071 Mar 27 17:04 /etc/selinux/targeted/policy/policy.24

1974394 8280 -rw-r–r– 1 root root 8477071 Mar 27 17:04 /etc/selinux/targeted/modules/active/policy.kern

1975018 2176 -rw-r–r– 1 root root 2225495 Mar 27 17:05 /etc/gconf/gconf.xml.defaults/%gconf-tree.xml

6、查找/etc目录下所有用户都没有写权限的文件

都没有写权限,非(…或… 或…)的关系,且要求为文件

[root@Centos6 ~ 09:50:34]#find /etc ! -type d -a ! -perm /222 -ls

7、查找/etc目录下至少有一类用户没有执行权限的文件

至少一类用户没有执行权限,对应的“非”关系是全部用户都有执行权限

find /etc ! -perm -111 -a ! -type d -ls

8、查找/etc/init.d目录下,所有用户都有执行权限,且其它用户有写权限的文件

都是且关系,使用权限法-113匹配

[root@Centos6 ~ 10:35:58]#find /etc/init.d -perm -113 -ls

1966176 0 lrwxrwxrwx 1 root root 11 Mar 27 17:00 /etc/init.d -> rc.d/init.d

压缩、解压缩及归档工具

compress [-dfvcVr] [-b maxbits] [file …]

-d: 解压缩,相当于uncompress,默认解压缩会删除压缩文件

-c: 结果输出至标准输出,不删除原文件

-v: 显示详情

uncompress .Z后缀压缩文件解压缩命令

zcat file.Z >file 利用zcat,实现保留压缩文件的同时解压文件

gzip [OPTION]… FILE …

不跟选项默认压缩文件,跟多个文件名分别压缩成对应文件名加后缀gz,并且删除源文件

-d: 解压缩,相当于gunzip

-c: 将压缩或解压缩的结果输出至标准输出

-#:1-9,指定压缩比,值越大压缩比越大,

zcat:不显式解压缩的前提下查看文本文件内容

实例:

gzip -c messages >messages.gz 压缩保留源文件

gzip -c -d messages.gz > messages 解压缩保留压缩文件

zcat messages.gz > messages 解压缩保留压缩文件

bzip2 [OPTION]… FILE …

bunzip2 解压缩

-k: keep, 保留原文件

-d:解压缩

-#:1-9,压缩比,默认为9

bzcat:不显式解压缩的前提下查看文本文件内容,用法可参考前面。

xz [OPTION]… FILE …

unxz 解压缩

-k: keep, 保留原文件

-d:解压缩

-#:1-9,压缩比,默认为6

xzcat: 不显式解压缩的前提下查看文本文件内容

zip/unzip 在windows中用的较多,在linux系统中用的较少。

zip命令的语法和linux风格的压缩工具有一点区别,zip可以对目录进行压缩。而linux风格的压缩工具只会对目录下的每个文件进行单独压缩。

zip -r 压缩后的文件名 要进行压缩的文件或目录

打包压缩

zip –r /testdir/sysconfig /etc/sysconfig/

解包解压缩

unzip sysconfig.zip

cat /var/log/messages | zip messages –

unzip -p message > message

压缩文件的命令用法都比较类似,不同的是较新的命令压缩比更加优越,并且提供了保留源文件的选项-k。但是同样的压缩命令都是针对单个文件的压缩而设定,如果要将多个文件压缩到一个压缩包,必须将多个文件进行打包,成为一个归档文件,压缩工具才能够进行压缩,归档命令时tar。

tar工具

tar(Tape ARchive,磁带归档的缩写)注意归档和压缩是不同的。

tar [OPTION]…

主选项(独占,只能使用一个,表明这次进行的是什么操作)

-c:建立一个压缩文件的参数指令(create 的意思);

-x:解开一个压缩文件的参数指令!

-t:查看 tarfile 里面的文件!

-r:向压缩归档文件末尾追加文件

-u:更新原压缩包中的文件

选项(指明这次操作要进行的附加操作)

-z:有gzip属性,即需要用 gzip 压缩

-j:有bz2属性,即需要用 bzip2 压缩

-Z:有compress属性的

-v :压缩的过程中显示文件(显示所有过程)!这个常用,但不建议用在背景执行过程!

-O:将文件解开到标准输出

-f :使用档名,请留意,在 f 之后要立即接档名!不要再加参数!例如使用『 tar -zcvfP tfile sfile』就是错误的写法,要写成『 tar -zcvPf tfile sfile』才对

-p :使用原文件的原来属性(属性不会依据使用者而变)

-P :可以使用绝对路径来压缩

-N :比后面接的日期(yyyy/mm/dd)还要新的才会被打包进新建的文件中

–exclude FILE:在压缩的过程中,不要将 FILE 打包

-f: 使用档案名字,切记,这个参数是最后一个参数,后面只能接档案名

常用组合:

 

# tar -cf all.tar *.jpg 将所有.jpg的文件打成一个名为all.tar的包。-c是表示产生新的包,-f指定包的文件名。

# tar -rf all.tar *.gif 将所有.gif的文件增加到all.tar的包里面去。-r是表示增加文件的意思。

# tar -uf all.tar logo.gif 更新原来tar包all.tar中logo.gif文件,-u是表示更新文件的意思。

# tar -tf all.tar 是列出all.tar包中所有文件,-t是列出文件的意思

# tar -xf all.tar 解压all.tar包中所有文件,-x是解压缩的意思

#tar -tf aaa.tar.gz 在不解压的情况下查看压缩包的内容

#tar –cvf jpg.tar *.jpg 将目录里所有jpg文件打包成tar.jpg

#tar –czf jpg.tar.gz *.jpg 将目录里所有jpg文件打包成jpg.tar后,并且将其用gzip压缩,生成一个gzip压缩过的包,命名为jpg.tar.gz

#tar –cjf jpg.tar.bz2 *.jpg 将目录里所有jpg文件打包成jpg.tar后,并且将其用bzip2压缩,生成一个bzip2压缩过的包,命名为jpg.tar.bz2

#tar –cZf jpg.tar.Z *.jpg 将目录里所有jpg文件打包成jpg.tar后,并且将其用compress压缩,生成一个umcompress压缩过的包,命名为jpg.tar.Z

 

#tar –xvf file.tar 解压 tar包

#tar -zxvf file.tar.gz 解压tar.gz

#tar -jxvf file.tar.bz2 解压 tar.bz2

#tar –Zxvf file.tar.Z 解压tar.Z

#tar -cpvf /PATH/TO/SOMEFILE.tar FILE… 创建归档 c 打包 p保留原文件属性 v可视化 f指定档案文件的名字

#tar -r -f /PATH/TO/SOMEFILE.tar FILE… 追加文件至归档: 注:不支持对压缩文件追加

#tar -t -f /PATH/TO/SOMEFILE.tar 查看归档文件中的文件列表

#tar -x -f /PATH/TO/SOMEFILE.tar

#tar -x -f /PATH/TO/SOMEFILE.tar -C /PATH/ -C指定解压到哪个目录

结合压缩工具实现:归档并压缩

-j: bzip2, -z: gzip, -J: xz

分割大的 tar 文件为多份小文件:

split –b 每份小压缩包多大 –d 要分割的压缩文件的文件名 分割后的文件名的前缀

命令会自动给分割后的文件添加后缀名

split -b 1M –d mybackup.tgz mybackup-parts 分割

cat mybackup-parts* > mybackup.tar.gz 合并

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:/96203

发表评论

登录后才能评论

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1823388528@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班

友情链接:万达招商  华宇招商  万达娱乐主管  万达娱乐招商  万达娱乐开户  万达主管QQ  万达招商  万达娱乐直属  万达注册  万达注册