Shell-基础部分

Shell基础

文章目录

1. Shell版本介绍

1. Shell脚本

1. 什么是Shell
现在我们使用的操作系统(windows,Mac OS,Android,iOS等)都是带图形界面的,简单直观,容易上手,对于专业用户(程序员,网管等)和普通用户都非常适用;计算机的普及离不开图形界面。
然而计算机的早期并没有图形界面,我们只能通过一个一个命令来控制计算机,这些命令有成百上千之多,且不说记住这些命令是十分困难,每天面对没有任何色彩的黑屏本身就是一件枯燥的事情;这个时候的计算机还远远谈不上炫酷和普及,只有专业人士才能使用。
对于图形界面,用户只需要点击某个图标就能启动某个程序;对于命令行,用户输入某个程序的名字(可以看做一个命令)就能启动某个程序。这两者的基本过程都是类似的,都需要查找程序在硬盘上的安装位置,然后将他们加载到内存运行。换句话说,图形界面和命令行要达到的目的是一样的,都是让用户控制计算机。然而,真正能够控制计算机硬件(CPU 内存 显示器)的只有操作系统内核(kernel),图形界面和命令行只是架设在用户和内核之间的一座桥梁。
由于安全 复杂 繁琐的原因,用户不能直接接触内核(也没有必要),需要另外开发一个程序,让用户直接使用这个程序;该程序的作用就是就接收用户的操作(点击图标 输入命令),并进行简单的处理,然后再传递给内核。如此一来,用户和内核之间就多了一层"代理",这层"代理"既简化了用户的操作,也保护了内核。
用户界面和命令行就是这个另外开发的程序,就是这层代理"代理"。在linux下,这个命令行就叫做shell

​ Shell Script,Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次

性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用

其他编程程序编辑的程序效率更高,毕竟它使用了Linux/Unix下的命令。

​ 换一种说法也就是,shell script是利用shell的功能所写的一个程序,这个程序是使用纯文本文件,将一些shell

的语法与指令写在里面,然后用正规表示法,管线命令以及数据流重导向等功能,以达到我们所想要的处理目的

2. shell作用详析
Shell除了能解释用户输入的命令,将他传递个内核,还可以:
1.调用其他程序,给其他程序传递数据或者参数,并获取程序的处理结果
2.在多个程序之间传递数据,把一个程序的输出作为另一个程序的输入
3.shell本身也可以被其他程序调用
由此可见,shell是将内核,程序和用户连接了起来

Shell本身支持的命令并不多,但是他可以调用其他程序吗,每一个程序就是一个命令,这使得Shell命令的数量可以无限扩展,其结果就是shell功能非常的强大,完全能够胜任Linux的日常管理工作,如文本或者字符串检索,文件的查找或创建,大规模软件的自动部署,更改系统设置,监控服务器性能,发送报警邮件,抓取网页内容,压缩文件等。

Shell并不是简单地堆砌命令,我们还可以在shell中编程,这和使用c++,Java,python等常见的编程语言没什么两样

shell虽然没有C/C++,java,Python强大,但是也支持了基本的编程元素,例如:

if..else选择结构,switch..case开关语句,for,while,util循环
变量,数组,字符串,注释,加减乘除,逻辑运算等概念
函数,包括用户自定义的函数和内置函数,例如(print,export eval)

站在这个角度讲,Shell 也是一种编程语言,它的编译器(解释器)是 Shell 这个程序。我们平时所说的 Shell,有时候是指连接用户和内核的这个程序,有时候又是指 Shell 编程。

Shell 主要用来开发一些实用的、自动化的小工具,而不是用来开发具有复杂业务逻辑的中大型软件,例如检测计算机的硬件参数、一键搭建Web开发环境、日志分析等,Shell 都非常合适
3. 常用的shell类型
sh、bash、csh、tcsh、ash

sh
sh 的全称是 Bourne shell,由 AT&T 公司的 Steve Bourne开发,为了纪念他,就用他的名字命名了。
sh 是 UNIX 上的标准 shell,很多 UNIX 版本都配有 sh。sh 是第一个流行的 Shell。

csh
sh 之后另一个广为流传的 shell 是由柏克莱大学的 Bill Joy 设计的,这个 shell 的语法有点类似C语言,所以才得名为 C shell ,简称为 csh。
Bill Joy 是一个风云人物,他创立了 BSD 操作系统,开发了 vi 编辑器,还是 Sun 公司的创始人之一。
BSD 是 UNIX 的一个重要分支,后人在此基础上发展出了很多现代的操作系统,最著名的有 FreeBSD、OpenBSD 和 NetBSD,就连 Mac OS X 在很大程度上也基于BSD。

tcsh
tcsh 是 csh 的增强版,加入了命令补全功能,提供了更加强大的语法支持。

ash
一个简单的轻量级的 Shell,占用资源少,适合运行于低内存环境,但是与下面讲到的 bash shell 完全兼容。

bash
bash shell 是 Linux 的默认 shell,本教程也基于 bash 编写。
bash 由 GNU 组织开发,保持了对 sh shell 的兼容性,是各种 Linux 发行版默认配置的 shell。
bash 兼容 sh 意味着,针对 sh 编写的 Shell 代码可以不加修改地在 bash 中运行。

尽管如此,bash 和 sh 还是有一些不同之处:
一方面,bash 扩展了一些命令和参数;
另一方面,bash 并不完全和 sh 兼容,它们有些行为并不一致,但在大多数企业运维的情况下区别不大,特殊场景可以使用 bash 代替 sh。
4. shell脚本格式
shell 脚本的格式
Shell 脚本文件的名称可以任意,但为了避免被误以为是普通文件,建议将 .sh 后缀加上,以表示是一个脚本文件。
shell 脚本中一般会出现三种不同的元素:
第一行的脚本声明(#!)用来告诉系统使用哪种 Shell 解释器来执行该脚本;
第二行的注释信息(#)是对脚本功能和某些命令的介绍信息,使得自己或他人在日后看到这个脚本内容时,可以快速知道该脚本的作用或一些警告信息;
第三、四行的可执行语句也就是我们平时执行的 Linux 命令了。

2. shell和shell脚本的区别

​ shell是什么呢?确切一点说,Shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解

释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用Shell来启动、

挂起、停止甚3至是编写一些程序。 Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是

一种命令语言,又是一种程序设计语言(就是你所说的shell脚本)。作为命令语言,它互动式地解释和执行用户输入

的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高阶语言中才具有的控制结构,包括循环

和分支。它虽然不是 Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、创建文档并以并行

的方式协调各个程序的运行。

3. 交互式shell和非交互式shell

​ 交互式模式就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交

互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。

​ shell也可以运行在另外一种模式:非交互式模式。在这种模式下,shell不与你进行交互,而是读取存放在文

件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。

如下

简单的实现系统巡检的命令
date
free –m
df –Th
写成一个简单的脚本test.sh

#!/bin/bash
date
free –m
df –Th
[root@master ~]# chmod +x test.sh
[root@master ~]# ./test.sh

4. 运行shell脚本的两种方法

1. 作为可执行的程序
给.sh文件可执行权限,然后./该名字执行即可 如:
[root@localhost ~]# vim test.sh  
[root@localhost ~]# ./test.sh 
Hello World 

test.sh文件里面写的内容为
#!/bin/bash
echo "Hello World !"

注意事项:
一定写成./test.sh,而不是test.sh,运行其他二进制的程序也一样,直接写成test.sh,linux系统会去path寻找有没有叫test.sh的,而只有/bin./sbin,/usr/sbin等都在path里,如果当前目录不在path里面,写成test.sh是会找不到命令的,要用./test.sh告诉系统,就在当前目录找。
2. 作为解释器参数
运行这种方式是,直接运行解释器,其参数就是shell脚本的文件名 如

/bin/sh test.sh
/bin/php test.php

这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

5. 查询指令是否为内建命令

type命令可以查看

type [-参数] name

选项和参数:

​ : 不加任何参数时,type会显示出name是尾部指令还是bash的内建命令

-t : 当加入-t参数时,type会将name以底下这些字样显示其意义

​ file --------------> 外部指令

​ alias ------------> 设置的别名 可以在shell和全局配置文件中添加或修改

​ builtin ------------> bash内建的指令

-p : 如果后面接的name为外部指令时,才会显示完整的文件名

-a : 会由PATH变量定义的路径中,将含有name的指令都列出来,包含alias

[root@localhost ~]# type ls
ls is aliased to `ls --color=auto'   # 未加任何的参数,列出ls的具体使用情况
[root@localhost ~]# type -t ls
alias                                # 加入-t参数,直接返回其意义,指明ls是设置的别名
[root@localhost ~]# type -a ls
ls is aliased to `ls --color=auto'   # 最先使用alias
ls is /usr/bin/ls                    # 找到外部指令ls的位置
[root@localhost ~]# type cd        
cd is a shell builtin                # shell的内建命令
[root@localhost ~]# 

注:当命令过于长一行写不下或者是看着不舒服想要换行书写时需要在最后面的命令上加入反斜杠 \换行书写即可。

[root@localhost ~]# cat  /etc/sysconfig/network-scripts/ifcfg-ens33 \
> >> a.txt
[root@localhost ~]# vim a.txt 

2. shell脚本常用的命令

1. 常用命令

1. cat,head,tail命令

1 求/etc/passwd文件第20行内容

[root@manager test1]# cat -n /etc/passwd | head -20 | tail -1

rev,tac命令

rev左右颠倒

tac上下颠倒

2. find命令
常用选项
            -name
            -type
            -user
            -nouser
            -group
            -nogroup
            -mtime
            -size

可以使用 -o 或者 -a 连接多个条件

可以使用-exec或者-ok来执行shell命令

 find /etc/ -name hosts -exec cp {} /tmp/ \;
如: 
 find /var/logs -type f -mtime +7 -exec rm {} \;

xargs

​ 在使用find命令的- exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递 给exec执行。不幸

的是,有些系统对能够传递给 exec的命令长度有限制,这样在 find命令运行几分钟之后,就会出现溢出错误。错

误信息通常是“参数列太长”或“参数列溢出”。

如:
[root@manager home]#  find / -name "core" -exec file {} \;
[root@manager home]#  find / -name "core" | xargs  file
3. 计划任务crond和crontab
*/10 * * * *   脚本|命令
4. & 命令

当在前台运行某个作业时,终端被该作业占据;而在后台运行作业时,它不会占据终端。

xclock -update 1 & 后台运行

关闭终端程序也会关闭

5. nohup命令

​ 如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用 nohup命令。该命令可以在你退出帐户之后继续运行相应的进程。 nohup就是不挂起的意思( nohang up)。

该命令的一般形式为

nohup command &

nohup xclock -update 1 &
6. shell的通配符
* 可以显示所有的匹配内容
? 匹配字符(可以是未知的字符)
[...][!...]  [a-z] [0-9] [!a12d]
{..} 



7. echo命令

双引号和单引号的区别
单引号
-e 使转义符生效 如: 解释\t \n含义
-n 不换行输出

字颜色:30—–37 
echo -e “\033[30m 黑色字 \033[0m” 
echo -e “\033[31m 红色字 \033[0m” 
echo -e “\033[32m 绿色字 \033[0m” 
echo -e “\033[33m 黄色字 \033[0m” 
echo -e “\033[34m 蓝色字 \033[0m” 
echo -e “\033[35m 紫色字 \033[0m” 
echo -e “\033[36m 天蓝字 \033[0m” 
echo -e “\033[37m 白色字 \033[0m”

字背景颜色范围:40—–47 
echo -e “\033[40;37m 黑底白字 \033[0m” 
echo -e “\033[41;37m 红底白字 \033[0m” 
echo -e “\033[42;37m 绿底白字 \033[0m” 
echo -e “\033[43;37m 黄底白字 \033[0m” 
echo -e “\033[44;37m 蓝底白字 \033[0m” 
echo -e “\033[45;37m 紫底白字 \033[0m” 
echo -e “\033[46;37m 天蓝底白字 \033[0m” 
echo -e “\033[47;30m 白底黑字 \033[0m”


改变提示符文件的颜色
[root@manager home]# echo -e "\033[40;32m"

报警声音
[root@manager home]# echo -e "\007 the bell ring"


printf命令
[root@manager home]# printf aa
aa[root@manager home]# printf "aa\n"
aa

格式化输出
[root@manager home]# printf "%s,%s,%d\n" hello world 123
hello,world,123

%s  字符串  %d十进制整数
8. read命令

​ 可以使用read语句从键盘或文件的某一行文本中读入信息,并将其赋给一个变量。如果只指定了一个变量,那

么 read将会把所有的输入赋给该变量,直至遇到第一个文件结束符或回车。

赋值

[root@manager home]# read name
zhangsan
[root@manager home]# echo $name
zhangsan

赋多值

[root@manager home]# read firstname lastname
huibin zhang
[root@manager home]# echo $firstname $lastname
huibin zhang

交互式

[root@manager home]# read -p "input a num: " var
input a num: 123
[root@manager home]# echo $var
123
9. | 管道命令

​ 管道(Pipe)实际是用于进程间通信的一段共享内存. 创建管道的进程称为管道服务器,连接到一个管道的进程为

管道客户机

1. 管道命令的两个作用

1.管道两边产生两个子进程

2.前一个进程的标准输出和后一个进程的标准输入

注意以下情况不能赋值

[root@7-1 tmp]# read a 
fdsa
[root@7-1 tmp]# echo $a
fdsa
[root@7-1 tmp]# echo 456 | read b
[root@7-1 tmp]# echo $b

【注】因为管道两边产生的是两个子进程,所以不能进行赋值输出
	 而分开写则是输出$a是read a的子进程,这样可以进行赋值并以原值输出


ps -f | cat
UID    PID PPID C STIME TTY     TIME CMD
root   14412 14405 0 04:56 pts/3  00:00:00 -bash
root   15485 14412 0 05:53 pts/3  00:00:00 ps -f
root   15486 14412 0 05:53 pts/3  00:00:00 cat
3个进程没有任何父子进程关系
如图:
bash ps -f | cat
1000 2000   3000
   echo 123 | read a
bash
|______ps -f > 
|______cat <
 
bash
|______echo 123 > 
|______read a <
10. 重定向(文件描述符)

​ 文件描述符:进程连接到文件时,获得的一个标记.当进程操作文件时,首先打开文件 获得打开文件的一个状态,给它

一个标记 成为文件描述符

0标准输入
1标准输出
2标准错误输出

> >> 定向符(重定向) >覆盖 >>追加

1> 标准正确输出,文件存在则覆盖,不存在则创建

1>> 标准正确输出,文件存在则追加,不存在则创建

2> 标准错误输出,文件存在则覆盖,不存在则创建

2>> 标准错误输出,文件存在则追加,不存在则创建

&> 标准正确和标准错误输出,文件存在则覆盖,不存在则创建

cat < /dev/sda > /dev/null 测试改变文件描述符

ls >cleanup.out 2>&1

在上面的例子中,我们将 ls命令的输出重定向到 cleanup .out文件中,而且其错误也 被重定向到相同的文件中。

2>&1 标准错误输出定向到标准正确输出

< 输入重定向 后边跟的是文件 > >>

<< here document 后边跟的是一个文本

如下
cat > x.txt << EOF 
\> sdfsadlkf
\> asdfsadhf
\> asfdhkasfd
\> EOF ------------直到遇到EOF结束

[root@manager tmp]# fdisk /dev/sda <<EOF
\> n
\> 
\> +200M
\> w
\> EOF
 
<<<here string 后边跟字符串 直接交给文本 如:
cat >x.txt <<<asdadad
cat x.txt
 
 

\> >> < << <<< 
11. tee命令

​ tee命令作用可以用字母 T来形象地表示。它把输出的一个副本输送到标准输出,另一个 副本拷贝到相应的文件

中。如果希望在看到输出的同时,也将其存入一个文件, 这种情况可以使用tee命令

如:
[root@manager home]# who | tee who.out
root     pts/1        2016-09-18 07:50 (192.168.10.102)
[root@manager home]# cat who.out 
root     pts/1        2016-09-18 07:50 (192.168.10.102)

[root@manager home]# find /etc -name hosts | tee aa.txt
/etc/hosts
[root@manager home]# cat aa.txt 
/etc/hosts


简而言之就是tee命令既可以让结果输出在文件里面也可以在终端中显示。

12. sort命令
[root@manager tmp]# cat aa.txt 
2
4
3
21
90
78
45
23
2
3
5
1
[root@manager tmp]# sort aa.txt   默认排序是按着第一字符大小进行排序
1
2
2
21
23
3
3
4
45
5
78
90
[root@manager tmp]# sort -n aa.txt  -n参数就是按着整体排序
1
2
2
3
3
4
5
21
23
45
78
90
[root@manager tmp]# sort -n -r aa.txt    按完整数字排序 降序
90
78
45
23
21
5
4
3
3
2
2
1
[root@manager tmp]# sort -u aa.txt  去掉重复值 
1
2
21
23
3
4
45
5
78
90

[root@manager tmp]# sort -t: -k3nr /etc/passwd
13. uniq命令(默认去掉连续的重复值)
[root@manager tmp]# cat aa.txt 
2
4
4
3
3
21
90
78
45
23
2
3
5
1
[root@manager tmp]# uniq aa.txt  连续的去掉
2
4
3
21
90
78
45
23
2
3
5
1
[root@manager tmp]# uniq -u aa.txt  显示未重复值
2
21
90
78
45
23
2
3
5
1
[root@manager tmp]# sort -n aa.txt  | uniq -u 排序去重
1
5
21
23
45
78
90

[root@manager tmp]# sort -n aa.txt  | uniq -d  显示重复行
2
3
4
[root@manager tmp]# sort -n aa.txt  | uniq -d -c  统计重复次数
      2 2
      3 3
      2 4
14. grep命令
--color 
-i   忽略大小写
-A  后几行
-B  前几行
-C  前后几行
-r   递归目录
-l   只显示匹配文件名
-x  完全一样
-n  显示行号
[root@manager tmp]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

[root@manager tmp]# grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash

[root@manager tmp]# grep halt$ /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt

[root@manager tmp]# grep -A 2 root /etc/passwd
[root@manager tmp]# grep -B 2 root /etc/passwd
[root@manager tmp]# grep -C 2 root /etc/passwd

统计存在root的行数
[root@manager tmp]# grep -c root /etc/passwd 
2

过滤root用户,并显示行号
[root@manager tmp]# grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
11:operator:x:11:0:operator:/root:/sbin/nologin

[root@manager tmp]# grep -r root /etc/  过滤所有文件
[root@manager tmp]# grep -rl root /etc/  列出文件名
[root@manager farm]# grep -rl  'localhost' /usr/local/apache/htdocs/farm/

[root@manager tmp]# cat aa.txt 
abc
ABC
xyz
XYZ 
[root@manager tmp]# grep abc aa.txt 
abc
[root@manager tmp]# grep -i abc aa.txt 
abc
ABC

[root@manager tmp]# grep -ix abc aa.txt 
ABC
[root@manager tmp]# grep -i ^abc$ aa.txt 
ABC
15. cut命令(截取)
[root@manager tmp]# cat aa.txt 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@manager tmp]# cut -c 1 aa.txt 
r
b
d
a
l
[root@manager tmp]# cut -c 1,3,5 aa.txt 
ro:
bnx
deo
amx
l::
[root@manager tmp]# cut -c 1-5 aa.txt 
root:
bin:x
daemo
adm:x
lp:x:

[root@manager tmp]# cut -d: -f 1 aa.txt 
root
bin
daemon
adm
lp

[root@manager tmp]# cut -d: -f 1,3,5 aa.txt 
root:0:root
bin:1:bin
daemon:2:daemon
adm:3:adm
lp:4:lp
[root@manager tmp]# cut -d: -f 1-5 aa.txt 
root:x:0:0:root
bin:x:1:1:bin
daemon:x:2:2:daemon
adm:x:3:4:adm
lp:x:4:7:lp

[root@manager tmp]# cat cc.txt 
aa cc
kk hh
[root@manager tmp]# cut -d' ' -f 1 cc.txt 
aa
kk


16. tr命令(替换)

• 大小写转换。
• 去除控制字符。
• 删除空行。

[a-z] a-z内的字符组成的字符串。

[A-Z] A-Z内的字符组成的字符串。

[0-9] 数字串

- s选项去掉重复字符

默认是将连续的字符去除,只保留一个
[root@manager etc]# echo "hellooooooo worlddddddd" | tr -s "[a-z]"
helo world

[root@manager tmp]# cat tt.txt 
hellooooooooooooo worldddddddddddddddddddd
[root@manager tmp]# cat tt.txt | tr -s '[a-z]'
helo world

以原样hello world显示就要将l选项筛选出去,使他就算是连续也不会被去除
[root@manager tmp]# cat tt.txt | tr -s '[a-k][m-z]'
hello world


删除空行
[root@manager home]# tr -s "[\n]" < aa.txt 
1.robin 19
2.zorro  30
3.tom  35

大小写转换
[root@manager home]# tr "[a-z]" "[A-Z]" < cc.txt 
1.ROBIN MAN
2.ZORRO MAN
3.TOM MAN

如果需要删除文件中^M,并代之以换行。使用命令:
tr -s "[\r]" "[\n]" < file.txt
17. wc命令

-l
-w
-c

[root@manager ~]# wc -l /etc/passwd
49 /etc/passwd

[root@manager tmp]# wc -w kk.txt 
3 kk.txt

[root@manager tmp]# wc -c kk.txt 
6 kk.txt


18. basename命令

显示末尾文件名

[root@manager ~]# basename /var/log/messages
messages
[root@manager ~]# basename /var/log/
log
19. split命令(分割文件)
[root@manager home]# cp /etc/passwd ./
[root@manager home]# split -l 2 passwd 
[root@manager home]# ls
passwd  xaa  xab  xac  xad  xae  xaf  xag  xah  xai  xaj
[root@manager home]# cat xaa
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

[root@manager tmp]# cat passwd | split -l 10
[root@manager tmp]# ls
passwd  xaa  xab  xac  xad  xae

[root@manager tmp]# split -b 1 aa.txt 
[root@manager tmp]# ls
aa.txt  xaa  xab  xac  xad  xae  xaf
20. join命令
有匹配域
[root@manager home]# cat aa.txt 
1.robin 19
2.zorro  30
3.tom  35
[root@manager home]# cat cc.txt 
1.robin man
2.zorro man
3.tom man
[root@manager home]# join aa.txt cc.txt 
1.robin 19 man
2.zorro 30 man
3.tom 35 man

​ 如果一个文件与另一个文件没有匹配域时怎么办?这时 join不可以没有参数选项,经常指定两个文件的- a选

项。下面的例子显示匹配及不匹配域。

[root@manager home]# join -a1 -a2 aa.txt cc.txt 
1.robin 19 man
2.zorro 30 man
3.tom 35 man
4.jerry man
[root@manager home]# join aa.txt cc.txt 
1.robin 19 man
2.zorro 30 man
3.tom 35 man
21. paste用法

​ paste将按行将不同文件行信息放在一行。缺省情况下, paste连接时,用空格或tab键分隔 新行中不同文本,

除非指定- d选项,它将成为域分隔符。

[root@manager home]# paste aa.txt cc.txt 
1.robin 19	1.robin man
2.zorro  30	2.zorro man
3.tom  35	3.tom man
4.jerry man

​ paste命令还有一个很有用的选项( -)。意即对每一个( -),从标准输入中读一次数据。 使用空格作域分隔

符,以一个4列格式显示目录列表。方法如下

[root@manager etc]# ls | paste -d" " - - - - - - 
22. eval命令

eval命令是一直执行命令直至执行完毕停止

[root@manager home]# vim cc.txt
1.robin man
2.zorro man
3.tom man

[root@manager home]# aa="cat cc.txt"
[root@manager home]# echo $aa
cat cc.txt
[root@manager home]# eval $aa
1.robin man
2.zorro man
3.tom man



[root@7-1 tmp]# echo $aa
cat cc.txt
[root@7-1 tmp]# aa='cat cc.txt'
[root@7-1 tmp]# echo $aa
cat cc.txt
[root@7-1 tmp]# aa=`cat cc.txt`
[root@7-1 tmp]# echo $aa
1.robin man 2.zorro man 3.tom man1
[root@7-1 tmp]# eval $aa
bash: 1.robin: command not found...
[root@7-1 tmp]# 


【注】若cc.txt中第一行是命令的话,则使用eval会继续执行第一条命令,然后输出结果在终端上
	 而echo $aa不会执行文件的第一条命令,会将cc.txt文件中的信心全部输出出来。
	 
	 eval只执行文件中的一条命令,默认是第一行的。若要执行文件中别的命令则需要使用别的指令使eval定向到那条命令然后再执行。

23. date命令
[root@manager tmp]# date
2016年 09月 15日 星期四 01:20:48 CST
[root@manager tmp]# date +%F
2016-09-15

[root@manager tmp]# date 月日时份年.秒
[root@manager tmp]# date -s "20161015 10:10:10"
20161015日 星期六 10:10:10 CST

[root@manager tmp]# date +%Y-%m-%d-%H-%M-%S
2016-09-20-13-58-09
24. logger命令
[root@manager tmp]# logger "hello i am robin"

自定日志保存位置
[root@manager tmp]# vim /etc/rsyslog.conf
local5.*                                                /tmp/test.log
[root@manager tmp]# service rsyslog restart

[root@manager tmp]# logger -p local5.err -t test  -f /tmp/test.log  hhhhhhh
-p日志级别
-t 标记
-f 日志位置
25. bc命令(支持小数运算)

整数

[root@manager ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
1+2
3
3-1
2
2*2
4
2/2
1
5%2
1
5^2
25

小数

[root@manager ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
scale=3  # 只有在输入此指令时才会使小数点后保留几位
7/3
2.333

进制转换

[root@manager ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
#ibase是input输入是几进制的数 
#obase是output输出是几进制的数
ibase=10;obase=2 
10
1010
2
10
ibase=8;obase=10
9
11
ibase=10;obase=16
11
B
上述和这种的都属于交互式操作

非交互式

[root@manager ~]# echo "1+2" | bc
3
[root@manager ~]# echo "scale=3;3/2" | bc
1.500
[root@manager ~]# echo "ibase=10;obase=2;7" | bc
111

[root@manager tmp]# echo "obase=8;19" | bc
23
[root@manager tmp]# echo "obase=2;F" | bc
1111

[root@manager tmp]# echo "2^10" | bc
1024

计算平方根

[root@manager ~]# echo "sqrt(100)" | bc
10

||逻辑或 前边命令失败执行后边命令
&&逻辑与 前边命令成功运行后边命令

pwd && echo ok
adfa && echo ok

pwd || echo ok
adfa || echo ok

2. 练习

1.统计当前系统中有多少个用户可以登录

[root@manager ~]# grep "/bin/bash$" /etc/passwd | wc -l
14
[root@manager ~]# grep -c "/bin/bash$" /etc/passwd 
14
[root@manager ~]# cut -d: -f 7 /etc/passwd | grep bash | uniq -c
     14 /bin/bash

2.取ip地址

[root@manager ~]# ifconfig eth2 | head -2 | tail -1 | cut -d':' -f 2 | cut -d' ' -f 1
[root@manager ~]# ifconfig eth2 | grep Bcast | cut -d':' -f 2 | cut -d' ' -f 1
172.16.20.1
[root@manager ~]# ifconfig | grep Bcast | cut -d':' -f 2 | cut -d' ' -f 1
172.16.20.1
172.16.20.201

3.使用stat命令查看文件状态,然后截取时间

[root@manager ~]# stat install.log
  File: "install.log"
  Size: 8003      	Blocks: 16         IO Block: 4096   普通文件
Device: 802h/2050d	Inode: 130307      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2016-09-09 06:29:21.250999892 +0800
Modify: 2016-09-09 06:30:57.320999775 +0800
Change: 2016-09-09 06:30:59.526999773 +0800

取时间
06:29:21
06:30:57
06:30:59

[root@manager ~]# stat /root/install.log | tail -3 | cut -d" " -f3 | cut -d'.' -f 1
18:02:07
09:54:49
09:54:49
[root@manager ~]# stat /root/install.log | tail -3 | cut -d" " -f1,3 | cut -d'.' -f 1
Access: 18:02:07
Modify: 09:54:49
Change: 09:54:49

4.将ip地址192.168.10.100转换成点分二进制

[root@manager ~]# echo "obase=2;192" | bc 
11000000
[root@manager ~]# echo "obase=2;168" | bc 
10101000
[root@manager ~]# echo "obase=2;10" | bc 
1010
[root@manager ~]# echo "obase=2;100" | bc 
1100100

5.将passwd文件按uid排序?按gid排序?
[root@manager ~]# sort -t: -k3n /etc/passwd
[root@manager ~]# sort -t: -k4n /etc/passwd




3. 作业

写一个 一键配置yum库脚本

[root@manager test1]# cat yum.sh
#!/bin/bash
#configure yum scripts

#mount cdrom
umount /yum
mount /dev/cdrom /yum

#configure yum
rm -rf /etc/yum.repos.d/*
touch /etc/yum.repos.d/yum.repo
cat > /etc/yum.repos.d/yum.repo <<EOF
[CentOS6.6]
name=server
baseurl=file:///yum
gpgcheck=0
enabled=1
EOF

#test yum
yum clean all
yum makecache



===========

#!/bin/bash
mount -t iso9660 /dev/cdrom /mnt/
cd /etc/yum.repos.d/
mkdir old
mv CentOS-* old/
touch loacl.repo
cat > /etc/yum.repos.d/local.repo <<EOF
[local_iso]
name=local iso
baseurl=file:///mnt
enabled=1
gpgcheck=0
EOF

cat >> /etc/fstab <<EOF
/dev/cdrom /mnt iso9660 defaults 0 0 
EOF

yum clean all
yum repolist

3. shell脚本基础支持及变量

1. 基础知识

1.shell脚本的格式注意事项

2.shell脚本文件的扩展名

3.shell脚本执行顺序以及产生后果(如出现错误)

a /tmp/test

rm –rf $a/*

4.用户身份的不同执行脚本的区别

普通用户若想执行脚本最低权限为rx才可以执行

root用户只需要x权限即可

5.shell种类的介绍(nologin和锁定区别)及用户切换切换shell方式(bash chsh -l)

nologin是不能进行远程登录
锁定是不允许登录

6.历史命令的介绍history

!! 执行历史命令中最后一条
!100 执行历史命令中的第一百条命令
!ser  执行历史命令中距离最后一条命令最近的以ser开头的命令
!$   执行最后一条命令 
alt+. 使用上一条命令中的最后的指令 和使用 esc+。功能一样

7.Shell退出时执行的命令.bash_logout

8.别名的介绍alias(以及命令的回顾)

2. 变量

1. 环境变量

​ 环境变量是一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。例如path,当要求

系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中

指定的路径去找。用户通过设置环境变量,来更好的运行进程

环境变量:系统在启动过程中预先指定好的一系列的变量.比如当前用户是谁 当前shell是什么 当前用户的家目录在

什么位置等等

2. 预定义变量

预定义变量:系统预定义好的 和进程名称 进程编号 进程参数 进程返回值相关

3.位置变量

位置变量和命令行参数相关

4.自定义变量

自定义变量(用户自己定义的变量)

1. 第一类 环境变量

环境变量 echo

env 查看所有环境变量

echo $变量名 输出变量

PATH
USER
HOME
HOSTNAME
PWD
UID
PS1
LANG=zh_CN.UTF8 (setup,yum groupinstall.系统时间)

set 查看所有变量(包括环境变量和非环境变量)

非环境变量:为用户定义的变量

export x=100 环境变量 可以被子进程所调用
y=200 非环境变量 不能被子进程所调用

环境变量和非境变量永久生效,写入配置文件

每个用户家目录下的环境变量配置文件:

.bash_history  保存用户执行过来历史命令,当用户退出时保存
.bash_logout  保存用户退出时执行的命令

.bash_profile  保存用户定义环境和启动项目,用户执行命令时的搜索路径
.bashrc  保存用户别名和函数

.bash_profile  登录级别环境配置文件
.bashrc  shell级别的环境配置文件

/etc/bashrc 全局shell级别环境配置文件
/etc/profile 全局登录级别环境配置文件

登录时加载的配置文件顺序

/etc/profile
.bash_profile
.bashrc
/etc/bashrc

question:
su - robin  和 su robin 切换帐号的区别:
answer:
1. su - robin 登录级别切换
2. su robin shell级别切换

su - 切换用户后,同时切换到新用户的工作环境中
su   切换用户后,不改变原用户的工作目录,及其他环境变量目录

用su -用户名的切用户的时候,他会把用户的环境变量也会读取出来,读取~/.bashrc文件
而su 不会

练习

1.当robin用户退出时,清除自己所有的历史命令

[root@manager robin]# vim /home/robin/.bash_logout
 rm -rf /home/robin/.bash_history
 history -c

2.设置别名myip 要求:所有用户可以调用这个别名

[root@manager robin]# vim /etc/bashrc 
alias myip="ifconfig eth2 | grep Bcast | cut -d':' -f 2 | cut -d' ' -f 1"

3.当一个用户登录时将这个用户登录的用户名,时间写入到/tmp/login.txt文件

[root@manager robin]# vim /etc/profile
echo "$USER" 'login' `date`  >> /tmp/login.txt
2. 第二类 预定义变量

$0 $$ $# $? $*

$0 进程名(如:/etc/init.d/network)
$$ 进程号(/var/run 模拟系统结束进程)
$# 位置参数的数量
$* 所有位置参数的内容
$? 命令执行后的返回状态.0为执行正确,非0为执行错误

[root@7-1 ~]# cat test.sh 
#!/bin/bash
echo $0    #  进程名(如:/etc/init.d/network)
echo $$    #  进程号(/var/run 模拟系统结束进程)
echo $#    #  位置参数的数量
echo $?    #  所有位置参数的内容
echo $*    #  命令执行后的返回状态.0为执行正确,非0为执行错误
[root@7-1 ~]# bash test
test/    test.sh  
[root@7-1 ~]# bash test.sh 
test.sh
2648
0
0

[root@7-1 ~]# bash test.sh 1 2 3
test.sh
2649
3
0
1 2 3
[root@7-1 ~]# 
3. 第三类 位置变量

位置变量: 和命令行参数相关 (命令后跟的参数$1-$9)

4. 第四类 自定义变量

自定义变量:当用户变量不够用时,自定义的变量

如下测试脚本

#!/bin/bash
cd /tmp
touch a.txt
ls –ld /tmp
du –sh /tmp

改为
#!/bin/bash
$DIR=/tmp
cd $DIR
touch a.txt
ls –ld $DIR
du –sh $DIR

练习

1.计算器 四则运算

./脚本 1 + 2
3

再进一步完善脚本read 命令的使用

[root@7-1 ~]# vim sum.sh
#!/bin/bash
echo $(($1 $2 $3))
[root@7-1 ~]# bash sum.sh 1+2
3


[root@7-1 ~]# vim sum.sh
#!/bin/bash
echo $(($*))
[root@7-1 ~]# bash sum.sh 1+2
3

[root@7-1 ~]# vim sum.sh
#!/bin/bash
echo "scale=2;$* " | bc
[root@7-1 ~]# bash sum.sh 1+2
3

[root@7-1 ~]# vim sum.sh
#!/bin/bash
read -p "number1:" num1
read -p "op: " op
read -p "number2: " num2
echo "scale=2;$num1 $op $num2" | bc

[root@7-1 ~]# bash sum.sh
number1:1
op: +
number2: 3
4


2.算式运算符
+、-、*、/、()

1.$((5+3))
2.$[ 5+3 ]



3.expr操作符:
+、-、\*、/、%取余(取模)
expr 1 + 2



4.let操作
a=1;b=2
let c=$a+$b
echo $c

export作用范围
父子shell的说明,及变量的定义

a.sh
#!/bin/bash
echo IN a.sh’
aa=123
./b.sh

b.sh
#!/bin/bash
echo ‘IN b.sh’
echo $aa

运行脚本方式的介绍
./a.sh
bash a.sh
source a.sh
. a.sh
source a.sh 和. a.sh

【注】
source. (点空格)作用是加载命令并不是执行,多用于加载函数库
./ bash 才是执行命令,可以直接执行可执行程序

 

别名   内部命令    外部命令 
[root@manager tmp]# type ls   别名
ls is aliased to `ls --color=auto'

[root@manager tmp]# type useradd   外部 产生子进程
useradd is /usr/sbin/useradd

[root@manager tmp]# type cd  内部  不产生子子进程在当前环境下运行
cd is a shell builtin

别名>外部命令>内部


利用当前的shell执行后边的脚本 如果没有外部命令 则不产生子进程
如测试脚本如下
cat aa.sh
\#!/bin/bash
cd /
pwd
 
./ aa.sh
. aa.sh
3. 变量命名规则
在定义变量时,变量名不加美元符号($,php语言中的变量需要)
【注】 变量$后面是{},不是其他括号
your_name="123456789"

【注】 变量名和等号之间不允许有空格

变量名命名规则(和python类似):
1.命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
2.中间不能有空格,可以使用下划线
3.不能使用标点符号
4.不能使用bash里的关键字(可用help命令查看保留关键字)


变量设定规则:
1. 变量与变量内容以一个等号来连接
2. 等号两边不能直接接空格符号
3. 变量内容若有空格符号可以使用双引号或者单引号将变量内容结合起来。
   双引号内的特殊字符如$等,可以保持原有的特性
   单引号内的特殊字符只能为一般字符(纯文本)
4. 变量名称只能是英文字母和数字,但是开头不能为数字
5. 可以使用跳脱字符反斜杠将特殊符号变成一般字符。
6. 在一串指令的执行中,还需要使用反引号或者$指令
7. 若该变量为扩增变量内容时,则可以使用$变量名称或$(变量)累加内容 如:path="$path":/home/bin 或 path=${path}:/home/bin
8. 若变量需要执行其他子程序时,则需要export来是变量变为环境变量
9. 通常大写字符为系统的默认变量,自行设定的变量可以使用小写字符
10. 取消变量的方法使用unset unset 变量名
不仅显式直接赋值,还可以用语句给变量赋值  如:
for file in `ls /etc`for file in $(ls /etc}
上述语句将/etc下目录的文件名循环出来
4. 使用变量

使用一个定义过的变量,只要在变量名前面加上美元符号($)即可:

your_name="123456"
echo $your_name
echo ${your_naeme}

注:
变量名外面的花括号是可选的,加不加都行。加花括号是为了帮助解释器识别变量的边界。
如:
for i in natasha harry sarah;
do
	echo "I am ${i}_father"
done

如果不给变量加上花括号,解释器会把 $i_father当成一个变量,但是其不存在的,所以输出结果就不是期待的那种情况。

已定义的变量,可以被重新定义

your_name="123"
echo $your_name
your_name="456"
echo $your_name
这样写是合法的,但第二次赋值的时候不能写$your_name="alibaba",使用变量的时候才加美元符($)。
5. 只读变量

使用readonly命令可以将变量定义为只读变量,只读变量的值不允许被改变

#!/bin/bash
myurl="https://www.google.com"
readonly myurl
myurl="https://www/baidu.com"

运行脚本:
[root@localhost ~]# ./test.sh 
./test.sh: line 4: myurl: readonly variable
6. 删除变量

使用unset命令可以删除变量,语法:

unset variable_name

变量在删除后不能被再次使用,unset命令不能删除只读变量。

实例:
#!/bin/sh
myUrl="https://www.runoob.com"
unset myUrl
echo $myUrl
myUrl1="https://www.baidu.com"
#unset myUrl1
echo $myUrl1


[root@localhost ~]# vim test.sh 
[root@localhost ~]# ./test.sh 

https://www.baidu.com

3. 函数库定义

函数库:将常用的变量定义到一个文件里 直接加载这个文件 就不用重复定义变量了

如系统中的确定与失败

子进程定义的变量能否被父进程集成

nologin shell 和 login shell
/etc/bashrc
/etc/bashrc
~/.bashrc
~/.bash_profile
1. read命令的使用

read命令:将脚本后边跟着的变量的值读取到脚本中
-p –t 参数的说明
如下边这个有趣的脚本

#!/bin/bash
read -p "请输入银行卡账号: " num
read -p "请输入银行卡密码: " -t 5 pass
echo 账号$num 密码$pass >> /tmp/haha.txt

yum install postfix
service postfix restart

#!/bin/bash
read -p "输入帐号: " account
stty -echo
read -p "输入密码: " -t 5  pass
stty echo
echo
echo "帐号:$account 密码:$pass" >> /tmp/login.txt
echo "帐号:$account 密码:$pass" | mail -s "auth" root@localhost


算式置换

a=10+20 
a=$((10+20))

命令置换(将命令执行结果赋给变量)

a=`date +%m%d`
a=$(date +%m%d) 推荐
[root@manager test1]# file=`ls `date +%F``  报错
[root@manager test1]# file=$(ls $(date +%F))
[root@manager test1]# echo $file
2016-09-20

原因

a=`ls `date +%m%d`` 该赋值失败
a=$(ls $(date +%m%d ))
2. 通配符

通配符是shell解释的 正则表达式是命令解释的

*   匹配任所有字符
?   匹配一个字符
[]  匹配一个范围
{}  如touch abc{a,b,c}{1..3}.txt

变量的引用
echo 命令介绍
echo -n -e参数说明 “”’’说明 \n \t
echo $
echo ’$’

[root@manager test1]# echo hello world;i am robin 报错

[root@manager test1]# echo "hello world;i am robin"
hello world;i am robin
[root@manager test1]# echo 'hello world;i am robin'
hello world;i am robin

[root@manager test1]# name=robin
[root@manager test1]# echo 'hello world;i am $name'
hello world;i am $name
[root@manager test1]# echo "hello world;i am $name"
hello world;i am robin


4. Test命令及判别语法

1. test命令的使用

语法:test EXPRESSION 或者 [ EXPRESSION ]

字符串判断(用于看用户有没有输入指定的变量 指定用户输入目录 )

-n 字符段长度是否非零的 如果结果为真值 返回值为0 如果结果为假值返回值非0

例:判断两个文件名字是否一致

mkdir /a /b
touch /a/x.txt /b/x.txt
[ "/a/x.txt"="/b/x.txt"] 可定错误不同 目录名称不同
应为
[ "$(basename /a/x.txt)"="$(basename /b/x.txt)" ]

test 整数

eq 等于
ge 大于等于
gt 大于
le 小于等于
lt 小于
ne 不等于

test 文件

ef 两个文件有相同的设备编号和inode编号 (判断硬链接)
touch aa 
ln aa bb
ls -i 
456733 aa 456733 bb

根据文件类型判断
-d 文件存在必须是个目录
-e 有文件名存在就行不管类型
-f 文件存在而且是个标准普通文件
-h 文件存在并且是否为符号链接文件
-r 判断文件权限是否有r权限
-w 写权限
-x 执行权限
【注】以上所有的命令都可以通过使用man手册进行查看,具体作用全部都有。
2. 条件判断语句
if cmd;如为真值
then
fi  结束 执行
如为假值则不执行



例
if [ -f /etc/passwd ]
then
  echo ok
fi



若文件不存 则 不执行

if useradd uu3
then 
  id uu3
fi
添加成功则显示用户信息

if [ -f /etc/ssh/sshd_config ]
then 
  service sshd start
else
  echo ssh is not install
fi
3. 练习

1.提示输入一个用户名字,判断该用户是否存在?存在显示其信息(uid gid 家目录 shell),不存在添加该帐号

#!/bin/bash
read -p "输入用户名: " username
if id $username &> /dev/null
then
	echo "用户存在,显示信息"
	grep $username  /etc/passwd | cut -d':' -f 1,3,4,6,7
else
	echo "用户$username不存在,添加用户"
	useradd $username
fi

2.提示输入文件路径及文件名,判断该文件是否存在,存在显示其详细信息,不存在创建该文件

[root@manager test1]# cat file.sh 
#!/bin/bash
read -p "输入完整文件名: " file
if [ -f $file ]
then
	echo "文件存在,显示文件信息"
	ls -l $file
else
	echo "文件不存在,创建文件"
	touch $file
fi


4. if语句的嵌套
if cmd
then
     ………
else 
          if cmd
          then 
              ……….
          else
              ………..
          fi
fi



if语句的完整写法
if cmd1
then
          run cmd1-1
          run cmd1-2
elif cmd2
then
          run cmd2-1
          run cmd2-2
elif cmd3
then  
             run cmd3-1
          run cmd3-2
else 
then
          run cmd4-1
          run cmd4-2
fi

100数字内猜数字游戏

#/bin/bash
guess=80
read -p "please insert yao number(range 1-100): " num
if [ $num -eq $guess ]
then
    echo "you are win!!!!"
else
    echo "you are lose!!!!"
fi

如果是猜随机数怎么办?($RANDOM).

正常情况应该为产生一个随机数,猜数人员有5次机会.这就需要用到循环语句,那么循环语句的结构式怎样的呢?带着上边的问题我们先学习一下循环语句,循环语句主要有两个循环语句for和while。

5. 作业及练习

1.判断tmp下是否存在普通文件aa.txt,文件存在则输出文件详细信息,文件不存在则创建文件

[root@7-1 work]# vim one.sh 
[root@7-1 work]# bash one.sh 
文件不存在,创建文件
[root@7-1 work]# bash one.sh 
文件存在
-rw-r--r--. 1 root root 0 Nov 26 14:49 aa.txt

#!/bin/bash

cd /tmp

filename=aa.txt

if [ -f $filename ]
then
        echo "文件存在"
        ls -l $filename
else
        echo "文件不存在,创建文件"
        touch $filename
fi

2.写脚本判断脚本后边的变量个数是否超过2个 不足提示变量不足,超过提示超过

#!/bin/bash

echo "$*"

echo "$#"

if [ $# -ge 2 ]
then
        echo "超过了"
else
        echo "变量不足"
fi
~       

3.提示用户输入一个变量值 判断输入的值是否为空

#!/bin/bash

read -p "请输入一个变量值:" var

if [ -z $var ]
then
        echo "$var值为空"
else
        echo "$var值不为空"
fi

4.从系统中搜索文件man.config是否存在,判断该文件和/root/install.log是否为硬链接

#!/bin/bash
name="man.config"

if [ -e $name ]
then
        if [ $name -h /root/install.log ]
        then
                echo  "为硬链接文件"
        else
                echo "不为硬链接文件"
        fi
else
        echo "该文件不存在"
fi

5.从系统搜索光盘镜像文件,如果有挂载使用 否则提示下载

#!/bin/bash

iso=`find /dev -name cdrom`

if [ -z "$iso" ]
then
        echo "no"
else
        mount -t iso9660 $iso /mnt
fi
~  

6.写一个文本文件/tmp/user.txt 内容为
帐号
密码
写一个交互式脚本,让用户输入帐号 密码,判断用户输入帐号密码是否正确,如果正确提示登录成功

#!/bin/bash

read  -p "请输入账号: " account

account1=`head -1 /tmp/user.txt`
password1=`tail -1 /tmp/user.txt`
if [ $account = $account1 ]
then
        echo "账号输入正确"
        read -p "请输入密码: " password
        if [ $password = $password1 ]
        then
                echo "密码输入正确"
        else
                echo "密码输入错误"
        fi
else
        echo "账号输入错误"
fi

7.写一个判断vsftpd是否正在运行的脚本

#!/bin/bash

systemctl status vsftpd > /dev/null
str=$?
if [  $str -eq 0 ]
then
        echo "正在运行"
else
        echo "没有运行"
fi

8.写一个判断内存使用是否大于50%的脚本


9.写一个检查系统中登录用户超过5个的脚本

#!/bin/bash

num=`who | wc -l`

if [ $num -ge 5 ]
then
        echo "超过5个"
else
        echo "未超过5个"
fi

10.完善你写过的yum库脚本


11.判断nmap命令是否存在 如果不存在则安装对应的软件包

#!/bin/bash

rpm -qa nmap
if [ $? -eq 0 ]
then
        echo "未安装"
else
        echo "已安装"
fi

12.查看光盘上有哪些软件没有安装,将没有安装的软件包,安装到系统中


13.如何判断一个目录为空目录


14.查看虚拟机的网络内有多少ip地址是活跃的,并且那些ip的ssh服务是开启的?


作业:
1.判断当前用户是否为root 如果为root用户启动ssh服务 如果非root切换用户提示用户启动服务

2.每隔3秒调用自己一次

3.分析下边脚本

a.sh

#!/bin/bash
echo $$
./a.sh | ./a.sh &

4.判断自己是否为重复运行脚本,如果为重复运行的脚本则自动退出(同一时间该脚本只有一个实例运行)

5. 循环语法

1. for循环语句

如下脚本

#!/bin/bash
for i in 1 3 5 7
do
     echo $i
     echo ok
done 


我们还可以将for循环读取的语句写到一个文件里如a.txt
#!/bin/bash
for I in `cat a.txt`
do
echo $i
echo ok
done

添加100个用户

[root@7-1 tmp]# for i in ab{1..100}
> do 
> useradd $ab{}^C
[root@7-1 tmp]# for i in {1..100}
> do
> useradd ab${i}
> done
[root@7-1 tmp]# cd /home/
[root@7-1 home]# ls
ab1    ab14  ab2   ab25  ab30  ab36  ab41  ab47  ab52  ab58  ab63  ab69  ab74  ab8   ab85  ab90  ab96  jack   tom
ab10   ab15  ab20  ab26  ab31  ab37  ab42  ab48  ab53  ab59  ab64  ab7   ab75  ab80  ab86  ab91  ab97  jean   zorro
ab100  ab16  ab21  ab27  ab32  ab38  ab43  ab49  ab54  ab6   ab65  ab70  ab76  ab81  ab87  ab92  ab98  jerry
ab11   ab17  ab22  ab28  ab33  ab39  ab44  ab5   ab55  ab60  ab66  ab71  ab77  ab82  ab88  ab93  ab99  king
ab12   ab18  ab23  ab29  ab34  ab4   ab45  ab50  ab56  ab61  ab67  ab72  ab78  ab83  ab89  ab94  ben   robin
ab13   ab19  ab24  ab3   ab35  ab40  ab46  ab51  ab57  ab62  ab68  ab73  ab79  ab84  ab9   ab95  boss  rose
[root@7-1 home]# 2%2

time 命令的使用

real墙上时间,也就是实际消耗时间多少

user用户态消耗的时间.

sys 系统底层消耗的时间(操作硬盘)

计算1-100的累加和(注意初始化值)

#!/bin/bash

result=0

for i in {1..100}
do

result=$(($i+$result))

done

echo $result

计算1-100奇数的累加和 偶数呢?

#!/bin/bash


for i in {1..100}
do
#jum=`echo "$i%2" | bc`
if [ `echo "$i%2" | bc` -eq 0 ]
then
        dum=$(($dum+$i))
else
        jum=$(($jum+$i))
fi
done
        echo "奇数和:$jum"
        echo "偶数和:$dum"
~                           

有没有更好的方式

seq 1 2 100 产生1-100个数字 步长为2 脚本就可以变得更简单了

for循环的另一种写法 模拟c语言的写法

for ((i=0;i<10;i++))
do
     echo $i
done


i+=2  i=i+2
i-=2  i=i-2
i*=2 i=i*2
i/=2 i=1/2

数值运算时这种写法更简单 如果文件处理for in的语法更容易写

好了 我们开始完成上边遗留的问题

猜数字给5次机会
又遇到问题.猜对了的情况下还让猜 这时应该跳出脚本 不在继续猜!!!又被打了…

#!/bin/bash

num=$(($RANDOM%100+1))

for i in {1..5}
do
        read -p "输入数字[1~100]:" guess

        if [ $guess -eq $num ]
        then
                echo "赢了"
                break
        elif [ $guess -gt $num ]
        then
                echo "大了"
        else
                echo "小了"
        fi

done
~     

break 和continue 跳出循环
break 跳出循环 脚本继续执行
continue 跳出本次循环,脚本继续执行
exit 退出脚本, 但是exit可以设置脚本返回值

遇到某些条件时这一次的循环跳出continue (如再来一个小游戏:大家说数字1-100 遇到被7整除和含有的7的数就跳出)

#!/bin/bash

while true
do
        read -p "input one number: " num
        res=`echo "$num%7" | bc`
        res1=`echo "$num/10" | bc`
        res2=`echo "$num%10" | bc`
        if [ $res -eq 0 -o $res2 -eq 7 -o $res1 -eq 7 ]
        then
                echo "you lose!"
                sleep 3
                break;
        else
                continue
                echo "continue games!"
        fi
done

2. select循环

select i in ls pwd whoami
do
     $i
done


[root@7-1 ~]# select i in ls pwd whoami
> do
> $i
> done
1) ls
2) pwd
3) whoami
#? 1
\		 Desktop    Downloads  initial-setup-ks.cfg  Pictures  Templates  test.sh  work
anaconda-ks.cfg  Documents  game.sh    Music		     Public    test	  Videos
#? 2
/root
#? 3
root
#? 

3. while和until循环

while 后边跟命令 条件为真值时循环

until 后边跟命令 条件为假值时循环

更多用while做死循环

语法

while cmd
do
list
done


如 true为真值 0
while true
do
     sleep
     echo ok
done


:空指令
死循环
while true
do
     :
done


不会死机 cpu发现为死循环 降低该进程优先级 
#!/bin/bash

#14.sh
x=0
while [ $x -lt 10 ]
do
echo $x
x=`expr $x + 1`
done


#!/bin/bash
#15.sh
sum=0
while [ $sum -lt 10 ]
do
sum=`expr $sum + 1`
useradd user$sum
echo "123456" | passwd --stdin user$sum
done

4. until语法

until cmd
do
list
done

#!/bin/bash
#16.sh
x=1
until [ $x -ge 10 ]
do
echo $x
x=`expr $x + 1`
done
相当于
x=1
while [ ! $x -ge 10 ]
do
echo $x
x=`expr $x + 1`
done

当用户robin 登录系统时 提示robin登录系统,记录用户信息(名字 时间  tty)


6. case分支语法及函数

1. case语法结构

case word in
pattern1)
list1
;;
pattern2)
list2
;;
... ...
patternN)
listN
;;
*)
list*
;;
esac

超市卖水果

#!/bin/bash
read –p “请输入你要查询的商品: ”var
case $var in
apple)
  echo "apple 1.4元每斤"
;;
orange)
  echo "orage 1.5元每斤"
;;
banana)
  echo "banana 1.6元每斤"
::
esac

/etc/init.d/sshd
用法:/etc/init.d/sshd {start|stop|restart|reload|condrestart|status}
服务用法的实现

#!/bin/bash
case $1 in
start)
 echo "start"
;;
stop)
 echo "stop"
;;
restart|reload)
 echo "restart"
;;
*)
 echo "Usage: $0 start|stop|restart"
esca

在这个基础上我们来实现一个小服务的脚本
nc 命令可以监听段口
nc –l 9999
好了,我们可以启动一个小服务了

#!/bin/bash
case $1 in
start)
  echo "start"
  nc –l 9999
;;
stop)
  echo "stop"
  pkill nc
;;
restart|reload)
  echo "restart"
  pkill nc
  nc –l 9999
;;
*)
  echo "Usage: $0 start|stop|restart"
esca

pidof取一个进程的pid

完善一些这个模拟服务的脚本

#!/bin/bash
start(){
    if [ -f /tmp/nc.lock ]
    then
        echo "nc is runing"
    else
        echo "start"
        nc -l 9999 &
        touch /tmp/nc.lock
    fi
}
stop(){
    if [ ! -f /tmp/nc.lock ]
    then
        echo "nc is not runing"
    else
        echo "stop"
        PID=$(pidof nc)
        kill -9 $PID
        rm -rf /tmp/nc.lock
    fi
}
case $1 in
start)
    start
;;
stop)
    stop
;;
restart)
    stop
    sleep 1
    start
;;
*)
    echo "Usage:$0 start|stop|restart"
esac

函数也可以让我们死机 如下
😦){ 😐:& };:

可以看我们的系统服务启动脚本了

2. 函数的参数

1. 函数外的参数也能被函数调用
#!/bin/bash
a=123
func(){
  echo $a
}

func   # 调用
2. 变量在函数内 外边也能调用
#!/bin/bash
func(){
     a=123
}

func
echo $a
3. 只在函数里调用 外部看不到 隔离变量
#!/bin/bash
func(){
local a=123
echo "in func"
echo $a
}

func
echo "out of func"
echo $a
4. 给函数传递参数
#!/bin/bash
sum(){
echo $(($1+$2))
}
sum 10 20
5. 如果命令参数传递给函数
#!/bin/bash
a=$1
b=$2
sum(){
echo $(($1+$2))
}

sum $a $b
执行a.sh 10 20

变量起名字别偷懒 起的有意义一些 让别人一目了然 如:argv1 argv2

#!/bin/bash
#注明 $1 $2 为脚本参数 以免脚本过长不知道那个$1 $2
argv=$1
argv=$2
sum(){
# $1 $2 为函数参数
func_argv1=$1
func_argv2=$2
echo $(($func_argv1+$func_argv2))
} 
sum $a $b

3. 练习脚本

提取主机名 函数
提取ip地址 函数 (多网卡)
检查自己主机启动什么服务的 函数

4. 练习和作业

1.添加user1-user50个用户.再添加过程中.如果这50个用户中有已存在的用户则显示The user is in system!!!如果不存在则添加,并且添加密码
能不能让上边的脚本加快执行速度?


2.打印一下矩阵

* * * * 
* * * * 
* * * *
* * * *

#!/bin/bash
do
       for ((j=1;j<=4;j++))
       do 
               echo -n  "* "
       done
       echo
done



#!/bin/bash
for i in `seq 1 4`
do
       for j in `seq 1 4`
       do
               echo -n "* "
       done
       echo
done

3.打印以下3角型

* 
* * 
* * * 
* * * * 
* * * * * 

#!/bin/bash
for ((i=1;i<=5;i++))
do
        for ((j=1;j<=i;j++))
        do
                echo -n "* "
        done

        echo 
done

4.按用户输入数字打印一下三角型 如输入行数

请输入行数:4
      * 
    * * * 
  * * * * * 
* * * * * * * 


#!/bin/bash

read -p "请输入行数:" lines

for ((i=1;i<=lines;i++))
do
        for ((k=1;k<=lines-i;k++))
        do
                echo -n "  "
        done
        for ((j=1;j<=$(($i*2-1));j++))
        do
                echo -n "* "
        done
        echo
done

倒三角

* * * * * 
* * * * 
* * * 
* * 
* 

#!/bin/bash
for ((i=5;i>=0;i--))
do
        for ((j=1;j<=i;j++))
        do
                echo -n "* "
        done

        echo 
done
      

5.按用户输入数字打印一下掏空等腰三角形

请输入行数:6
          * 
        *   * 
      *       * 
    *           * 
  *               * 
* * * * * * * * * * * 




#!/bin/bash

read -p "请输入行数:" lines

for ((i=1;i<=lines;i++))
do
        for ((k=1;k<=lines-i;k++))
        do
                echo -n "  "
        done
        for ((j=1;j<=$(($i*2-1));j++))
        do
        if [ $j -eq 1 -o $j -eq $(($i*2-1)) -o $i -eq $lines ]
        then
                echo -n "* "
        else
                echo -n "  "

        fi
        done
        echo
done

梯形


圣诞树


6.打印9x9乘法表如下格式

1 x 1 = 1	
1 x 2 = 2	2 x 2 = 4	
1 x 3 = 3	2 x 3 = 6	3 x 3 = 9	
1 x 4 = 4	2 x 4 = 8	3 x 4 = 12	4 x 4 = 16	
1 x 5 = 5	2 x 5 = 10	3 x 5 = 15	4 x 5 = 20	5 x 5 = 25	
1 x 6 = 6	2 x 6 = 12	3 x 6 = 18	4 x 6 = 24	5 x 6 = 30	6 x 6 = 36	
1 x 7 = 7	2 x 7 = 14	3 x 7 = 21	4 x 7 = 28	5 x 7 = 35	6 x 7 = 42	7 x 7 = 49	
1 x 8 = 8	2 x 8 = 16	3 x 8 = 24	4 x 8 = 32	5 x 8 = 40	6 x 8 = 48	7 x 8 = 56	8 x 8 = 64	
1 x 9 = 9	2 x 9 = 18	3 x 9 = 27	4 x 9 = 36	5 x 9 = 45	6 x 9 = 54	7 x 9 = 63	8 x 9 = 72	9 x 9 = 81	


#!/bin/bash

for ((i=1;i<=9;i++))
do
        for ((j=1;j<=i;j++))
        do
                echo -en "$j x $i = $(($i*$j))\t" 

        done
        echo

done



#!/bin/bash

for ((i=1;i<=9;i++))
do
        for ((j=1;j<=i;j++))
        do
        	if [ $j -eq 2 -a \( $i -eq 2 -o $i -eq 3 \)]
          	then
          		echo -n "$j x $i = $(($i*$j))  " 
			else
				echo -en "$j x $i = $(($i*$j)) "
			fi
        done
        echo

done

7.计算12345经过加减乘除等于15的式子

1 + 2 + 3 + 4 + 5 = 15
1 - 2 * 3 + 4 * 5 = 15
1 * 2 * 3 + 4 + 5 = 15


#!/bin/bash

for i in + - \* /
do
        for j in + - \* /
        do
                for m in + - \* /
                do
                        for n in + - \* /
                        do
                                if [ $((1 $i 2 $j 3 $m 4 $n 5 )) -eq 15 ]
                                then
                                        echo "1 $i 2 $j 3 $m 4 $n 5 = $((1 $i 2 $j 3 $m 4 $n 5 ))"
                                #else
                                #       echo "false"
                                fi
                        done
                done
        done
done 

8.写一个脚本监控你的/分区,当你的/分区的剩余空间小于10G时.给root管理员发一封邮件(测试时可以再某个文件里写一句话)

#!/bin/bash


while true
do
        if [ `df -T | grep /boot | awk {'print $5'}` -gt 204800 ]
        then
                echo "磁盘可以正常使用"
                exit
        else
                echo "超出范围"
fi
done

9.测试网络中有多少个ip是活跃,并且查询那些80端口开放


#!/bin/bash


for i in {1..254}
do
	( if ping -c 1 10.10.11.$i &> /dev/null
	then
		echo "10.10.11.$i online" >> /tmp/ok.txt
		nmap 10.10.11.$i |grep '80/tcp' >> /tmp/ok.txt
	else
		echo "10.10.11.$i is offline"
	fi ) &
done

10.判断自己是否为重复运行脚本,如果为重复运行的脚本则自动退出(同一时间该脚本只有一个实例运行)


11.mysql的备份脚本(mysqldump + binlog日志)

#!/bin/bash

#全备
mysqldump -u root -p123 --all-databases > /backup/full-`date +%F`.sql 2>/dev/null
#刷新日志
mysqladmin -u root -p123 flush-logs 2> /dev/null
#备份binlog
cd /usr/local/mysql/data
num=`wc -l master1.index | cut -d' ' -f 1`
#num=$(($num-1)) 
tar -zcf /backup/binlog-`date +%F`.tar.gz $(head -$(($num-1))  master1.index)


7. 变量替换及数组

1. 变量替换

(可以用if实现 这是另外一种方式)

1. ${parameter:-word}

若 parameter 为空或未设置,则用 word 代替 parameter 进行替换,parameter 的值不变

# a=1

# unset b
# a=${b:-3}
# echo $a

# a=1
# b=2
# a=${b:-3}
# echo $a
# echo $b
2. ${parameter:=word}

若 parameter 为空或未设置,则 parameter 设为值 word

# a=1
# unset b
# a=${b:=3}
# echo $a
# echo $b

# a=1
# b=2
# a=${b:=3}
# echo $a
# echo $b
3. ${parameter:+word}

若 parameter 设置了,则用 word 代替 parameter 进行替换,parameter 的值不变

# a=1
# unset b
# a=${b:+3}
# echo $a
# echo $b
#
# a=1
# b=2
# a=${b:+3}
# echo $a
# echo $b
4. ${parameter:?message}

若 parameter 为空或未设置,则 message 作为标准错误打印出来,这可用来检查变量是否正确设置

# unset a
# ${a:?unset a}
-bash: a: unset a


字符串切片,替换
$ a=12345678
$ echo ${a:5}         截取第五位以后的
678
$ echo ${a:3:4}       从第三位向后保留四位
4567
$ a=123456123789
$ echo ${a#1*3}       最短匹配截取,必须从第一位开始截取
456123789
$ echo ${a##1*3}      最长匹配截取
789
$ a=123
$ echo ${#a}          表示$var的长度
3
$ a=123456123789
$ echo ${a/1/}        第一次匹配的被替换(去掉)  
23456123789
$ echo ${a//1/}       全局的匹配被替换
2345623789
$ echo ${a/1/x}       把第一个1替换为x
x23456123789
$ echo ${a//1/x}      把所有的1替换为x
x23456x23789

2. 数组

shell的数组分为普通数组和关联数组

1. 普通数组

只能以数字作为数组

1.定义数组

[root@manager ~]# ary=(a b c)

2.数组取值

[root@manager ~]# echo ${ary[0]}
a
[root@manager ~]# echo ${ary[1]}
b
[root@manager ~]# echo ${ary[2]}
c
[root@manager ~]# echo ${ary[3]}

[root@manager ~]# echo $ary
a

3.设置数组的值为字符串

[root@manager ~]# ary=("robin" "zorro" "lucy")
[root@manager ~]# echo ${ary[0]}
robin
[root@manager ~]# echo ${ary[1]}
zorro
[root@manager ~]# echo ${ary[2]}
lucy

4.取数组所有值

[root@manager ~]# ary=("robin" "zorro" "lucy")
[root@manager ~]# echo ${ary[@]}
robin zorro lucy

或者
[root@manager ~]# echo ${ary[*]}
robin zorro lucy

5.数组的重新赋值

[root@manager ~]# ary[0]="jerry"
[root@manager ~]# echo ${ary[0]}
jerry

6.删除数组赋值

[root@manager ~]# unset ary[0]
[root@manager ~]# echo ${ary[0]}

7.删除数组

[root@manager ~]# unset ary
[root@manager ~]# echo ${ary[@]}

8.统计数组成员个数

[root@manager ~]# ary=("robin" "zorro" "lucy")
[root@manager ~]# echo ${#ary[@]}
3

9.统计数组成员字符个数

[root@manager ~]# ary=("robin" "zorro" "lucy")
[root@manager ~]# echo ${#ary[1]}
5
[root@manager ~]# echo ${#ary[2]}
4

10.数组切片

[root@manager ~]# ary=("robin" "zorro" "lucy")
[root@manager ~]# ary=("robin" "zorro" "lucy" "tom" "jerry")
[root@manager ~]# echo ${ary[@]:1:2}
zorro lucy
[root@manager ~]# echo ${ary[@]:1:3}
zorro lucy tom

11.数组成员切片

[root@manager ~]# echo ${ary[0]:1:2}
ob
[root@manager ~]# echo ${ary[0]:1:3}
obi
[root@manager ~]# echo ${ary[0]:1:4}
obin
[root@manager ~]# echo ${ary[1]:2:2}
rr

12.遍历数组所有的值

[root@manager ~]# for i in ${ary[@]}; do echo $i; done
a
b
c


2. 关联数组

Bash支持关联数组,它可以使用字符串作为数组索引,有时候采用字符串索引更容易理解。

1.利用内嵌索引-值列表的方法

[root@manager ~]# declare -A ary
[root@manager ~]# ary=([robin]=beijing [zorro]=shanghai)
[root@manager ~]# echo ${ary[robin]}
beijing
[root@manager ~]# echo ${ary[zorro]}
shanghai

2.使用独立的索引-值进行赋值

[root@manager ~]# ary[jack]=hebei
[root@manager ~]# ary[rose]=henan
[root@manager ~]# echo ${ary[jack]}
hebei
[root@manager ~]# echo ${ary[rose]}
henan

3.取数组值

[root@manager ~]# echo ${ary[*]}
shanghai beijing

4.取数组的键

[root@manager ~]# echo ${!ary[*]}
zorro robin

5.获取所有键值对

[root@manager ~]# for key in ${!ary[@]}
do
	echo "$key = ${ary[$key]}"
done
zorro = shanghai
robin = beijing
3. 练习

1.排序 数字
134 223 45 98 76 243 8 6 1 47

#!/bin/bash

arr=(134 223 48 98 76 243 8 6 1 47)
echo "数组初始数据为:" ${arr[@]}
len=${#arr[@]}
echo "数组长度为:" $len
for ((i=0;i<$len;i++))
do
        for((j=0;j<len-i-1;j++))
        do
                t=$[$j+1]
                if [[ ${arr[$j]}  -gt ${arr[$t]} ]]
                then
                        tmp=${arr[$j]}
                        arr[$j]=${arr[$t]}
                        arr[$t]=$tmp
                 fi
        done
done
echo "排序后的数据为:" ${arr[@]}


[root@7-1 work]# vim paixu.sh
[root@7-1 work]# bash paixu.sh 
数组初始数据为: 134 223 48 98 76 243 8 6 1 47
数组长度为: 10
排序后的数据为: 1 6 8 47 48 76 98 134 223 243
[root@7-1 work]# 

2.石头剪刀布游戏

#!/bin/bash

menu="
0.石头
1.剪刀
2.布
请输入您的拳法[0|1|2]: "

guess=("石头" "剪刀" "布")
ccount=0
pcount=0

while [ $ccount -lt 2 -a  $pcount -lt 2 ]
do
	num1=$(($RANDOM%3))
	compute=${guess[$num1]}
		
	read -p "$menu" num2
	player=${guess[$num2]}
	
	declare -A win_case
	win_case=(["石头"]="剪刀" ["剪刀"]="布" ["布"]="石头")
	
	echo "$player $compute"
	#echo ${win_case[$player]}
	#echo ${win_case[$compute]}
	
	
	if [ ${win_case["$compute"]} == "$player" ]
	then
		ccount=$(($ccount+1))
		echo "compute is win $ccount"
	elif [ ${win_case[$player]} == "$compute" ]
	then
		pcount=$(($pcount+1))
		echo "player is win $pcount"
	else
		echo "平局"
	fi
done
if [ $ccount -eq 2 ]
then
	echo "compute is win"
elif [ $pcount -eq 2 ]
then
	echo "player is win"
fi

8. ssh远程操作及终端控制

1.tput命令

tput 可以操作光标,定位光标

tput sc 保存光标位置

tput rc 返回光标位置

tput cols 读取列数

tput lines 读取行数

tput cup lines cols

tput civis # 光标不可见

tput cnorm # 光标可见

2. 定位倒计时

#!/bin/bash
col=`tput cols`
line=`tput lines`
ncol=$(($col/2))
nline=$(($line/2))
tput sc                          爆炸
for i in {1..1000}
do
	usleep $i
	tput cup $nline $ncol
	echo "$i"
done
tput cup $nline $ncol
echo "爆炸"
for i in {1..10}
do
	usleep 100000
	echo -e "\a"
	
done
tput rc


3. ssh远程脚本

1. expect非交互式
脚本代码如下

#!/usr/bin/expect  

set timeout 30  

spawn ssh -l username 192.168.1.1  

expect "password:"  

send "ispass\r"  

interact  

##############################################  
1. [#!/usr/bin/expect]

这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。

注意:这一行需要在脚本的第一行。

2. [set timeout 30]

基本上认识英文的都知道这是设置超时时间的,现在你只要记住他的计时单位是:秒

3. [spawn ssh -l username 192.168.1.1]

spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。所以不要用 “which spawn“之类的命令去找spawn命令。好比windows里的dir就是一个内部命令,这个命令由shell自带,你无法找到一个dir.com 或 dir.exe 的可执行文件。

它主要的功能是给ssh运行进程加个壳,用来传递交互指令。

4. [expect “password:”]

这里的expect也是expect的一个内部命令,有点晕吧,expect的shell命令和内部命令是一样的,但不是一个功能,习惯就好了。这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是前面设置的30秒

5. [send “ispass\r”]

这里就是执行交互动作,与手工输入密码的动作等效。

温馨提示: 命令字符串结尾别忘记加上 “\r”,如果出现异常等待的状态可以核查一下。

6. [interact]

执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。如果你只是登录过去执行一段命令就退出,可改为[expect eof]

2. shell脚本嵌套expect脚本
cat ssh.sh

#!/bin/bash
pass=123
/usr/bin/expect <<EOF
set timeout 30
spawn scp /root/install.log 192.168.1.1:/home
expect "password:"
send "$pass\r"
expect eof
EOF

添加用户natasha  密码redhat

终端控制

#!/bin/bash
gnome-terminal --geometry=34x8+0+0 -e /tmp/aa.sh
gnome-terminal --geometry=34x8+700+0 -e /tmp/aa.sh
gnome-terminal --geometry=34x8+0+700 -e /tmp/aa.sh
gnome-terminal --geometry=34x8+700+700 -e /tmp/aa.sh

9. 正则表达式

find grep sed awk vim
python php

正则表达式
算术表达式

1+2 3*5 1+2*3 (1+2)*3

正则表达式在匹配的时候一定要有一定规律,否则无法匹配 如下

特定的模式

A B C … … -> a b c … …
ABC ADC AEC … …
ab abb abbb abbbb abbbb… …
正则表达式的匹配过程

如:
	grep halt /etc/passwd

grep命令是linux下的行过滤工具,其参数繁多,

grep – print lines matching a pattern (将符合样式的该行列出)

◎语法: grep [options]

PATTERN [FILE…]

grep用以在file内文中比对相对应的部分,或是当没有指定档案时,

由标准输入中去比对。 在预设的情况下,grep会将符合样式的那一行列出。

其中egrep就等同于grep -E

常用参数
-A 匹配行的后多少行
-B 匹配行的前多少行
-C 前后行
-c 统计匹配行
-i 忽略大小写匹配
-E 扩展正则
-n 显示匹配行行号
-x 显示完全匹配的行
-v 取反

如下文件 a.txt
我要找到含有ABC ADC AEC 的行
asdfasdf ABC aasdajsd
afdafjal ADC qqweqeqwe
qweqe AEC adfajf

grep A.C a.txt
这里的.称为元字符

元字符

. 匹配除换行符之外的任意单个字符,awk中可以匹配换行符
* 匹配任意一个(包括零个)在它前面的字符
如下
a
ab
ac
abb
abc
abbc
abbbbbbbbbbbc

grep ab* b.txt
grep ab*c b.txt
grep a* b.txt
[root@7-1 day2]# grep ab* cc.txt 
a
ab
ac
abb
abc
abbc
abbbbbbbbbbbc
[root@7-1 day2]# grep ab*c  cc.txt 
ac
abc
abbc
abbbbbbbbbbbc
[root@7-1 day2]# grep a*c cc.txt 
ac
abc
abbc
abbbbbbbbbbbc


* 任意一个字符出现一次到多次
asadfsadfc
ac
afdsdfasdfasdfasdfc
aacc
aaaaaa1ccccccccc2aaaaaaaaaa3ccccccccc4

grep a.*c c.txt

[root@7-1 day2]# grep a.*c dd.txt 
asadfsadfc
ac
afdsdfasdfasdfasdfc
aacc
aaaaaa1ccccccccc2aaaaaaaaaa3ccccccccc4

.

[…] 匹配方括号中的任意一个字符,^为否定匹配, -表示字符的范围

acc
a.c
abc
a2c
a6c
a7c
a8c

grep [6789]c a.txt
grep [1-9]c a.txt
grep [^1-9]c a.txt
[root@7-1 day2]# grep [6789]c ee.txt
a6c
a7c
a8c
[root@7-1 day2]# grep [1-9]c ee.txt
a2c
a6c
a7c
a8c
[root@7-1 day2]# grep [^1-9]c ee.txt
acc
a.c
abc



1+2
1-2
1*2
1/2
grep[+-*/]’ a.txt

这种类型过滤内容时,由于减号代表的是范围,所以减号要么在最前面要么在最后面
[root@7-1 day2]# grep '[+-*/]' ff.txt 
grep: Invalid range end
[root@7-1 day2]# grep '[-+-*/]' ff.txt 
grep: Invalid range end
[root@7-1 day2]# grep '[-+*/]' ff.txt 
1+2
1-2
1*2
1/2
[root@7-1 day2]# grep '[+*/-]' ff.txt 
1+2
1-2
1*2
1/2


“^” 代表的是以...开头的字符
“$” 代表的是以...结尾的字符

^和$
root
aroot
roota

grep ^root a.txt
grep root$ a.txt
grep ^root$ a.txt

只包含3个字符?

最少包3个字符?

匹配空行?显示行号?

多个空格的空行?

grep "\t"是不行的,应该输入一个正在的制表符,方法为先按 CTRL+V,再按 Tab 键。

[root@7-1 work]# grep ^...$ test1.txt 
[root@7-1 work]# grep ^...$ test1.txt 


\ 转义字符

abc
a,c

grep a\,c a.txt
[root@7-1 day2]# grep a\,c gg.txt 
a,c

扩展元字符
+ 匹配前面的正则表达式的一次出现或多次出现

a
ab
abb
abbb

egrep ab+ a.txt

[root@7-1 day2]# grep -E ab+ hh.txt 
ab
abb
abbb
[root@7-1 day2]# egrep  ab+ hh.txt 
ab
abb
abbb

? 前边字符出现0或1次

y
yes
Y
Yes
? 的作用就是只要[]中的字母包含文件里的数据的字母就可以过滤出来
egrep [Yy][es]? a.txt

| 替代方案l
company
companies

egrep compan'[y|iess]' a.txt
egrep compan’(y|iess)’a.txt

或关系,含有y或者iess都会被过滤出来

{n,m}匹配出现的n到m次数, {n}匹配出现n次。{n,}匹配至少出现n次
大多数awk都不支持,用于POSIX egrep和POSIX awk

aaaa    4
aaaaa   5
aaaaaa  6
aaaaaaa 7

egrep a\{4,5\} a.txt

括号里的代表的是次数,不是行数

字符类

[Ww]hat
\.H[12345]

字符的范围

[a-z]
[0-9]
[Cc]hapter[1-9]
[-+*/]
[0-1][0-9][-/][0-3][0-9][-/][0-9][0-9]

[root@manager test5]# grep -E "(15:[0-2][0-9]|15:4[0-5]:)" /var/log/secure

排除字符类
[^0-9]

重复出现的字符

5
10
50
100
500
1000
5000
[15]0*
[15]00*

字符的跨度

* 与 \{n,m\}

电话号码的匹配

[0-9]\{3,4\}-[0-9]\{7,8\}

[root@7-1 day3]# cat a.txt
0476-89542563
0897-15586325
[root@7-1 day3]# grep  "[0-9]\{3,4\}-[0-9]\{7,8\}" a.txt 
0476-89542563
0897-15586325

分组操作

compan(y|ies)

sed和awk

sed和awk用于处理文本,在linux中大量操作都涉及到文本,如系统日志,应用程序日志.批量处理时对配置文件做修

改.操作文件时有些文件的语法不规范,如messages有空格分隔 :分隔 分号分隔 ,号分隔

如apache日志,分隔符不明显,而且分割时都是特殊字符,提取时我们可能只要ip 访问目标地址 访问时间 还有格式修

改,sed主要处理不规范的格式改为规范.

sed是一个“非交互式的”面向字符流的编辑器,awk是一种负责模式匹配的程序设计语言,它的典型示例是将数据

转换成格式化的报表。

sed流媒体编辑器的使用

练习文本:

John Daggett, 341 King Road, Plymouth MA
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Falls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
(名字 街道 城市 大州)

dos2unix 文件转换
unix2dos
在windows和linux之间文本格式互转的工具
linux \n
windows \n\r 换行

语法

sed ‘args’ file.txt file2.txt 但是官方文档称args为命令

sed ‘cmd’ file.txt file.txt

替换

sed ‘s/old/new/’ file1.txt 结果显示在屏幕上原文件不变

sed 's/MA/Massachusett/' file1.txt  

格式调整

sed 's/ MA/, Massachusetts/' file1.txt

多条处理

sed 's/ MA/, Massachusetts/ ; s/ PA/, Pennsylvania/' file1.txt

或者

sed -e 's/ MA/, Massachusetts/' -e 's/ PA/, Pennsylvania/' file1.txt

脚本支持
脚本:sedsrc

s/ MA/, Massachusetts/
s/ PA/, Pennsylvania/
s/ CA/, California/
s/ VA/, Virginia/
s/ OK/, Oklahoma/
sed -f sedsrc file1.txt

保存输出

sed -f sedsrc file1.txt > newfile.txt

阻止输入行自动显示

sed -n 's/MA/Massachusetts/p' file1.txt
带有-n参数时:
[root@7-1 day2]# sed -n 's/MA/Massachusetts/p' jj.txt 
s/ Massachusetts/, Massachusetts/

不带有-n参数时:
[root@7-1 day2]# sed  's/MA/Massachusetts/p' jj.txt 
s/ Massachusetts/, Massachusetts/
s/ Massachusetts/, Massachusetts/
s/ PA/, Pennsylvania/
s/ CA/, California/
s/ VA/, Virginia/
s/ OK/, Oklahoma/


由此可见 -n参数的作用是阻止输出全部,只打印匹配的那条信息

awk的简单使用

语法

awk{主输入循环}’file

输出每个人的名字

awk{print $1}file

第二列 默认分隔符(一个空格 多个空格 一个制表符 多个制表符) 所以,显示

awk{print $2}file

指定分隔符

awk –F, ‘{ print$1 }’ file1.txt

//匹配功能

匹配包含MA的行

awk ‘/MA/’ file1.txt

还想要用户名字

awk ‘/MA/{print $1}’ file1.txt

取root用户的pid

awk –F: ‘/root/{print $1 $3}’/etc/passwd

匹配字符串 $1~表示匹配第一个字段

awk –F: ‘$1~/root/{print $3 $1}’/etc/passwd

找到所有uid并求出和

[root@7-1 work]# cat test2.sh 
#!/bin/bash

num=`awk -F: '{print $3 }' /etc/passwd | wc -l`

res=0

for i in `awk -F: '{print $3 }' /etc/passwd`

do
	
	res=$(($res+$i))

done

echo $res

[root@7-1 work]# bash test2.sh 
89636

练习:
ps aux rss总和?

awk取ip地址 ?

ifconfig eth2 | awk -F':| +' '/Bcast/{print $4}'

1.正则对照表

正则表达式分为三类(man grep可以看到,分别是basic RegExs,extended RegExs,perl RegExs)

1. 正则表达式分类

1、基本的正则表达式(Basic Regular Expression 又叫 Basic RegEx 简称 BREs)

2、扩展的正则表达式(Extended Regular Expression 又叫 Extended RegEx 简称 EREs)

3、Perl 的正则表达式(Perl Regular Expression 又叫 Perl RegEx 简称 PREs)

2.Linux 中常用文本工具与正则表达式的关系

1)grep 支持:BREs、EREs、PREs 正则表达式

grep 指令后不跟任何参数,则表示要使用 ”BREs“
grep 指令后跟 ”-E" 参数,则表示要使用 “EREs“
grep 指令后跟 “-P" 参数,则表示要使用 “PREs"

2)egrep 支持:EREs、PREs 正则表达式

egrep 指令后不跟任何参数,则表示要使用 “EREs”
egrep 指令后跟 “-P" 参数,则表示要使用 “PREs"

3)sed 正则表达式特点

sed 文本工具支持:BREs、EREs
sed 指令默认是使用"BREs"
sed 命令参数 “-r ” ,则表示要使用“EREs"

4)Awk(gawk)正则表达式特点

Awk 文本工具支持:EREs
awk 指令默认是使用 “EREs"

字符说明Basic RegExExtended RegExpython RegExPerl regEx
转义\\\\
^匹配行首,例如’^dog’匹配以字符串dog开头的行(注意:awk 指令中,’^'则是匹配字符串的开始)^^^^
$匹配行尾,例如:’^、dog ′ 匹 配 以 字 符 串 d o g 为 结 尾 的 行 ( 注 意 : a w k 指 令 中 , ′ '匹配以字符串 dog 为结尾的行(注意:awk 指令中,' dogawk’则是匹配字符串的结尾)$$$$
^$匹配空行^$^$^$^$
^string$匹配行,例如:’^dog$'匹配只含一个字符串 dog 的行^string$^string$^string$^string$
<匹配单词,例如:’<frog’ (等价于’\bfrog’),匹配以 frog 开头的单词<<不支持不支持(但可以使用\b来匹配单词,例如:’\bfrog’)
>匹配单词,例如:‘frog>’(等价于’frog\b '),匹配以 frog 结尾的单词>>不支持不支持(但可以使用\b来匹配单词,例如:‘frog\b’)
<x>匹配一个单词或者一个特定字符,例如:’<frog>’(等价于’\bfrog\b’)、’<G>’<x><x>不支持不支持(但可以使用\b来匹配单词,例如:’\bfrog\b’
()匹配表达式,例如:不支持’(frog)’不支持(但可以使用,如:dog()()()
匹配表达式,例如:不支持’(frog)’不支持(同())不支持(同())不支持(同())
匹配前面的子表达式 0 次或 1 次(等价于{0,1}),例如:where(is)?能匹配"where" 以及"whereis"不支持(同?)
?匹配前面的子表达式 0 次或 1 次(等价于’{0,1}’),例如:'whereis? '能匹配 “where"以及"whereis”?不支持(同?)不支持(同?)不支持(同?)
?当该字符紧跟在任何一个其他限制符(*, +, ?, {n},{n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个"o",而 ‘o+’ 将匹配所有 ‘o’不支持不支持不支持不支持
.匹配除换行符(’\n’)之外的任意单个字符(注意:awk 指令中的句点能匹配换行符)..(如果要匹配包括“\n”在内的任何一个字符,请使用:’(^$)|(.)..(如果要匹配包括“\n”在内的任何一个字符,请使用:’ [.\n] ’
*匹配前面的子表达式 0 次或多次(等价于{0, }),例如:zo* 能匹配 "z"以及 “zoo”****
+匹配前面的子表达式 1 次或多次(等价于’{1, }’),例如:'whereis+ '能匹配 “whereis"以及"whereisis”+不支持(同+)不支持(同+)不支持(同+)
+匹配前面的子表达式 1 次或多次(等价于{1, }),例如:zo+能匹配 "zo"以及 “zoo”,但不能匹配 “z”不支持(同+)+++
{n}n 必须是一个 0 或者正整数,匹配子表达式 n 次,例如:zo{2}能匹配不支持(同{n}){n}{n}{n}
{n,}“zooz”,但不能匹配 "Bob"n 必须是一个 0 或者正整数,匹配子表达式大于等于 n次,例如:go{2,}不支持(同{n,}){n,}{n,}{n,}
{n,m}能匹配 “good”,但不能匹配 godm 和 n 均为非负整数,其中 n <= m,最少匹配 n 次且最多匹配 m 次 ,例如:o{1,3}将配"fooooood" 中的前三个 o(请注意在逗号和两个数之间不能有空格)不支持(同{n,m}){n,m}{n,m}{n,m}
x|y匹配 x 或 y,例如: 不支持’z|(food)’ 能匹配 “z” 或"food";’(z|f)ood’ 则匹配"zood" 或 “food”不支持(同x|y)x|yx|yx|y
[0-9]匹配从 0 到 9 中的任意一个数字字符(注意:要写成递增)[0-9][0-9][0-9][0-9]
[xyz]字符集合,匹配所包含的任意一个字符,例如:’[abc]'可以匹配"lay" 中的 ‘a’(注意:如果元字符,例如:. *等,它们被放在[ ]中,那么它们将变成一个普通字符)[xyz][xyz][xyz][xyz]
[^xyz]负值字符集合,匹配未包含的任意一个字符(注意:不包括换行符),例如:’[^abc]’ 可以匹配 “Lay” 中的’L’(注意:[^xyz]在awk 指令中则是匹配未包含的任意一个字符+换行符)[^xyz][^xyz][^xyz][^xyz]
[A-Za-z]匹配大写字母或者小写字母中的任意一个字符(注意:要写成递增)[A-Za-z][A-Za-z][A-Za-z][A-Za-z]
[^A-Za-z]匹配除了大写与小写字母之外的任意一个字符(注意:写成递增)[^A-Za-z][^A-Za-z][^A-Za-z][^A-Za-z]
\d匹配从 0 到 9 中的任意一个数字字符(等价于 [0-9])不支持不支持\d\d
\D匹配非数字字符(等价于 [^0-9])不支持不支持\D\D
\S匹配任何非空白字符(等价于[^\f\n\r\t\v])不支持不支持\S\S
\s匹配任何空白字符,包括空格、制表符、换页符等等(等价于[ \f\n\r\t\v])不支持不支持\s\s
\W匹配任何非单词字符 (等价于[^A-Za-z0-9_])\W\W\W\W
\w匹配包括下划线的任何单词字符(等价于[A-Za-z0-9_])\w\w\w\w
\B匹配非单词边界,例如:‘er\B’ 能匹配 “verb” 中的’er’,但不能匹配"never" 中的’er’\B\B\B\B
\b匹配一个单词边界,也就是指单词和空格间的位置,例如: ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的’er’\b\b\b\b
\t匹配一个横向制表符(等价于 \x09和 \cI)不支持不支持\t\t
\v匹配一个垂直制表符(等价于 \x0b和 \cK)不支持不支持\v\v
\n匹配一个换行符(等价于 \x0a 和\cJ)不支持不支持\n\n
\f匹配一个换页符(等价于\x0c 和\cL)不支持不支持\f\f
\r匹配一个回车符(等价于 \x0d 和\cM)不支持不支持\r\r
\匹配转义字符本身""\\\\
\cx匹配由 x 指明的控制字符,例如:\cM匹配一个Control-M 或回车符,x 的值必须为A-Z 或 a-z 之一,否则,将 c 视为一个原义的 ‘c’ 字符不支持不支持\cx
\xn匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长,例如:’\x41’ 匹配 “A”。’\x041’ 则等价于’\x04’ & “1”。正则表达式中可以使用 ASCII 编码不支持不支持\xn
\num匹配 num,其中 num是一个正整数。表示对所获取的匹配的引用不支持\num\num
[:alnum:]匹配任何一个字母或数字([A-Za-z0-9]),例如:’[[:alnum:]] ’[:alnum:][:alnum:][:alnum:][:alnum:]
[:alpha:]匹配任何一个字母([A-Za-z]), 例如:’ [[:alpha:]] ’[:alpha:][:alpha:][:alpha:][:alpha:]
[:digit:]匹配任何一个数字([0-9]),例如:’[[:digit:]] ’[:digit:][:digit:][:digit:][:digit:]
[:lower:]匹配任何一个小写字母([a-z]), 例如:’ [[:lower:]] ’[:lower:][:lower:][:lower:][:lower:]
[:upper:]匹配任何一个大写字母([A-Z])[:upper:][:upper:][:upper:][:upper:]
[:space:]任何一个空白字符: 支持制表符、空格,例如:’ [[:space:]] ’[:space:][:space:][:space:][:space:]
[:blank:]空格和制表符(横向和纵向),例如:’[[:blank:]]‘ó’[\s\t\v]’[:blank:][:blank:][:blank:][:blank:]
[:graph:]任何一个可以看得见的且可以打印的字符(注意:不包括空格和换行符等),例如:’[[:graph:]] ’[:graph:][:graph:][:graph:][:graph:]
[:print:]任何一个可以打印的字符(注意:不包括:[:cntrl:]、字符串结束符’\0’、EOF 文件结束符(-1), 但包括空格符号),例如:’[[:print:]] ’[:print:][:print:][:print:][:print:]
[:cntrl:]任何一个控制字符(ASCII 字符集中的前 32 个字符,即:用十进制表示为从 0 到31,例如:换行符、制表符等等),例如:’ [[:cntrl:]]’[:cntrl:][:cntrl:][:cntrl:][:cntrl:]
[:punct:]任何一个标点符号(不包括:[:alnum:]、[:cntrl:]、[:space:]这些字符集)[:punct:][:punct:][:punct:][:punct:]
[:xdigit:]任何一个十六进制数(即:0-9,a-f,A-F)[:xdigit:][:xdigit:][:xdigit:][:xdigit:]

1.验证用户名和密码

("^[a-zA-Z]\w{5,15}$")正确格式:
"[A-Z][a-z]_[0-9]" 组成,并且第一个字必须为字母6~16位;

2.验证电话号码

("^(\d{3,4}-)\d{7,8}$") 

正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;

3.验证手机号码

"^1[3|4|5|7|8][0-9]\\d{8}$"

4.验证身份证号(15位或18位数字)

"\d{14}[[0-9],0-9xX]"

5.验证Email地址

("^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$")

6.只能输入由数字和26个英文字母组成的字符串

("^[A-Za-z0-9]+$")

7.整数或者小数

^[0-9]+([.][0-9]+){0,1}$

8.只能输入数字

"^[0-9]*$"

9.只能输入n位的数字

"^\d{n}$"

10.只能输入至少n位的数字

"^\d{n,}$"

11.只能输入m~n位的数字

"^\d{m,n}$"

12.只能输入零和非零开头的数字

"^(0|[1-9][0-9]*)$"

13.只能输入有两位小数的正实数

"^[0-9]+(\.[0-9]{2})?$"

14.只能输入有1~3位小数的正实数

"^[0-9]+(\.[0-9]{1,3})?$"

15.只能输入非零的正整数

"^\+?[1-9][0-9]*$"

16.只能输入非零的负整数

"^\-[1-9][0-9]*$"

17.只能输入长度为3的字符

"^.{3}$"

18.只能输入由26个英文字母组成的字符串

"^[A-Za-z]+$"

19.只能输入由26个大写英文字母组成的字符串

"^[A-Z]+$"

20.只能输入由26个小写英文字母组成的字符串

"^[a-z]+$"

21.验证是否含有^%&’,;=?$"等字符

"[%&',;=?$\\^]+"

22.验证一年的12个月

"^(0?[1-9]|1[0-2])$"正确格式为:"01"~"09"和"10"~"12"

23.验证一个月的31天

"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01""09""10""29"和“30”~“31”

24.获取日期正则表达式

\\d{4}[|\-|\.]\d{\1-\12}[|\-|\.]\d{\1-\31}日?

评注:可用来匹配大多数年月日信息

25.匹配空白行的正则表达式

\n\s*\r

评注:可以用来删除空白行

26匹配HTML标记的正则表达式

<(\S*?)[^>]*>.*?</>|<.*? />

评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

27.匹配首尾空白字符的正则表达式

^\s*|\s*$

评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式

28.匹配网址URL的正则表达式

[a-zA-z]+://[^\s]*

评注:网上流传的版本功能很有限,上面这个基本可以满足需求

29.匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线)

^[a-zA-Z][a-zA-Z0-9_]{4,15}$

评注:表单验证时很实用

30.匹配腾讯QQ号

[1-9][0-9]{4,}

评注:腾讯QQ号从10 000 开始

31.匹配中国邮政编码

[1-9]\\d{5}(?!\d)

评注:中国邮政编码为6位数字

32.匹配ip地址

([0-9]{1,3}\.){3}[0-9]

评注:提取ip地址时有用

33.匹配MAC地址

([A-Fa-f0-9]{2}\:){5}[A-Fa-f0-9]

2. 正则练习题

正则表达式及字符处理
1.使用grep显示出/usr/share/dict/words文件中,例如显示出所有含有fish的行:

[root@manager test5]# grep fish /usr/share/dict/words

2.使用grep显示出/usr/share/dict/words文件中,输出任何包含fish的所有行,还要输出紧接着这行的上下各两行的内容

[root@manager test5]# grep -C 2  fish /usr/share/dict/words

3.使用grep显示出/usr/share/dict/words文件中,来显示出在words文件中有多少行含有fish。

[root@manager test5]# grep -c  fish /usr/share/dict/words
[root@manager test5]# grep fish /usr/share/dict/words | wc -l

4.使用grep显示出/usr/share/dict/words文件中,显示出那些行含有fish,并将行号一块输出,看一看starfish在哪行

[root@manager test5]# grep -n  fish /usr/share/dict/words
[root@manager test5]# grep -xn  starfish /usr/share/dict/words

5.想列出/usr/share/dict/words中包含先有字母t然后有一个元音字母,之后是sh的单词,命令为

[root@manager test5]# grep -x t[aeiou]sh /usr/share/dict/words

6.在/usr/share/dict/words文件中,创建可以符合abominable,abominate,anomie和atomize的正则表达式,但是不要选到别的单词

[root@manager test5]# grep -xE '(abominable|abominate|anomie|atomize)' /usr/share/dict/words
[root@manager test5]# grep -xE 'a[bnt]omi(nabl|nat|z)?e' /usr/share/dict/words
[root@manager test5]# grep -xE 'a[bnt]omi(na(bl|t)|z)?e' /usr/share/dict/words

7.在/usr/share/dict/words文件中包含多少先有字母t然后有一个元音字母,之后是sh的单词,只输出数量

grep -c t[aeiou]sh /usr/share/dict/words 

8.列出/usr/share/dict/words中刚好包含16个字母的单词

[root@manager test5]# grep -xE '[a-zA-Z_]{16}' /usr/share/dict/words 
[root@manager test5]# grep -xE '\w{16}' /usr/share/dict/words 

9.我们将要使用/usr/share/doc文件夹来完成
列出/usr/share/doc/bash-* 文件夹中,所有包含单词expansion的文件

[root@manager test5]# grep -rl "expansion" /usr/share/doc/

10. SED

1. sed的使用

sed文档
元字符
. 匹配除换行符之外的任意单个字符,awk中可以匹配换行符

例:
abc adc aec
a.c
1. *匹配0到多个前边字符
a
ab
ac
abb
abc
abbc
abbbbbbbbbbbc
sed 's/ab*/x/' a.txt  匹配a开头b出现0到多次



asdfsdkjfhskc
ac
asdfjslkfjslfjslfjsfljc
a23113131c
aacc
aaaaaaa1ccccccccc2aaaaaaaaaaa3c4
sed 's/a.*c/x/' a.txt 匹配a0-多个c结尾的字段 *的贪婪性尽可能长的c
2. […] 匹配方括号中的任意一个字符,^为否定匹配, -表示字符的范围
acc
a.c
abc
a2c
a6c
a7c
a8c

sed 's/a.c/x/' a.txt
sed 's/a[67c89]c/x/' a.txt
sed 's/a[1-9]c/x/' a.txt
sed 's/a[^1-9]c/x/' a.txt
1+2
1-2
1*2
1/2

sed 's/1[+-*/]2/x/' a.txt -号报错
sed 's/1[-+*/]2/x/' a.txt

^ 作为正则表达式的第一个字符,匹配行的开始。在awk中可以嵌入换行符

$ 作为正则表达式的最后一个字符,匹配行的结尾。在awk中可以嵌入换行符

root
aroot
roota

sed 's/root/x/' a.txt
sed 's/^root/x/' a.txt
sed 's/root$/x/' a.txt
sed 's/^root$/x/' a.txt
sed 's/^...$/x/' a.txt 只包含3个字符
sed 's/.../x/' a.txt 最少包含3个字符
sed 's/^$/x/' a.txt  sed不能匹配换行符 匹配空行
sed 's/^ *$/x/' a.txt 多个空格的行
3. {n,m} 匹配出现的n到m次数, {n}匹配出现n次。{n,}匹配至少出现n次(看扩展)

\ 转义字符

a/b
sed 's/a\/b/x\/y/' tt.txt
我们可以替换分隔符
sed 's@a/b@x/y@' tt.txt
sed 's;a/b;x/y;' tt.txt
任意的3个字符 都可以 避免产生冲突
date +%Y/%m/%d | sed ‘s@/@:@g’  g全局替换
4. 扩展元字符
1. + 匹配前面的正则表达式的一次出现或多次出现
a
ab
abb
abbb

sed 's/abb*/x/' a.txt
sed -r 's/ab+/x/' a.txt
2. ? 匹配前面的正则表达式的零次出现或一次出现
y
yes
Y
Yes

sed -r 's/[yY](es)?/x/' a.txt
3. | 可以匹配前面的或后面的正则表达式(替代方案)

() 替换方案 对正则表达式分组

company
companies
compan(y|ies)
[abc] (a|b|c) 某些情况下一样 还有分组功能后边会用到
4. {n,m} 匹配出现的n到m次数, {n}匹配出现n次。{n,}匹配至少出现n次
sed -r 's/a/!/' a.txt  只替换第一次匹配到的
sed -r 's/a{4}/!/' a.txt
sed -r 's/a{4,6}/!/' a.txt
sed -r 's/a{,4}/!/' a.txt
sed -r 's/a{5,}/!/' a.txt
5. 匹配一个字符出现0-1次 基本正则也可以实现.{,1}

sed ‘s/元字符在这里起作用匹配/±|则不再起元字符作用/’

编写sed脚本 要求如下
原始			完成后
apple			banana
banana			orange
一条命令完成
是不是我们想的结果?

为什么产生上边的问题:
首先sed在运行中会维护一段内存空间,这段内存空间称为模式空间:
模式空间存储被替换的文件,默认是按行为单位
如上文件读取过程
  首先进入模式空间s-----apple  替换为banana
 				在执行s-----banana 替换为orange
				结果apple被替换成orange  没有-n参数 输出终端上
  第二条进入模式空间  第一条命令匹配不上,第二条匹配 banana
被替换为orange 
5. 寻址上的全局透视(定址)

sed将命令应用于每个输入行,它可以指定零个、一个或两个地址。每个地址都是一个描述模式、行号或者行寻址

符号的正则表达式。(默认全文寻址)

范例file2.txt
.TS
Beijing,CN
.TE
Shanghai,CN

guangzhou,CN
shenyang,CN

sed ‘2s/CN/China/’file2.txt
sed '/Beijing/s/CN/China/' file2.txt
sed$s/CN/China/’file2.txt
sed ‘/^\.TS/,/^\.TE/s/CN/China/’file2.txt(避免中间出现)
sed '4,6s/CN/China/' file2.txt
sed '4,$s/CN/China/' file2.txt
sed '4,/guangzhou/s/CN/China/' file2.txt
6. 删除命令d

删除所有的行 d

1.只删除第一行

1d

2.使用寻址符号$,删除最后一行

$d

3.删除空行,正则表达式必须封闭在斜杠//当中

/^$/d

4.删除.TS 和.TE 标记的tbl 输入

/^\.TS/,/^\.TE/d

5.删除第五行到结尾所有的行

5,$d

6.混合使用行地址和模式地址

$ sed '1,/^$/d' file2.txt

7.删除除了那些行以外的行

1,5!d
7.分组命令
.TS
Beijing,CN
.TE
Shanghai,CN

guangzhou,CN
shenyang,CN

sed ‘/^\.TS/,/^\.TE/s/,/:/ ; /^\.TS/,/^\.TE/s/CN/China/ file2.txt


使用分组
sed '/^\.TS/,/^\.TE/{ s/,/:/ ; s/CN/china/ }' file2.txt
8. 练习

文件:datafile

Steve Blenheim:238-923-7366:95 Latham Lane, Easton, PA 83755:11/12/56:20300
Betty Boop:245-836-8357:635 Cutesy Lane, Hollywood, CA 91464:6/23/23:14500
Igor Chevsky:385-375-8395:3567 Populus Place, Caldwell, NJ 23875:6/18/68:23400
Norma Corder:397-857-2735:74 Pine Street, Dearborn, MI 23874:3/28/45:245700
Jennifer Cowan:548-834-2348:583 Laurel Ave., Kingsville, TX 83745:10/1/35:58900
Jon DeLoach:408-253-3122:123 Park St., San Jose, CA 04086:7/25/53:85100
Karen Evich:284-758-2857:23 Edgecliff Place, Lincoln, NB 92086:7/25/53:85100
Karen Evich:284-758-2867:23 Edgecliff Place, Lincoln, NB 92743:11/3/35:58200
Karen Evich:284-758-2867:23 Edgecliff Place, Lincoln, NB 92743:11/3/35:58200
Fred Fardbarkle:674-843-1385:20 Parak Lane, DeLuth, MN 23850:4/12/23:780900
Fred Fardbarkle:674-843-1385:20 Parak Lane, DeLuth, MN 23850:4/12/23:780900
Lori Gortz:327-832-5728:3465 Mirlo Street, Peabody, MA 34756:10/2/65:35200
Paco Gutierrez:835-365-1284:454 Easy Street, Decatur, IL 75732:2/28/53:123500
Ephram Hardy:293-259-5395:235 CarltonLane, Joliet, IL 73858:8/12/20:56700
James Ikeda:834-938-8376:23445 Aster Ave., Allentown, NJ 83745:12/1/38:45000
Barbara Kertz:385-573-8326:832 Ponce Drive, Gary, IN 83756:12/1/46:268500
Lesley Kirstin:408-456-1234:4 Harvard Square, Boston, MA 02133:4/22/62:52600
William Kopf:846-836-2837:6937 Ware Road, Milton, PA 93756:9/21/46:43500
Sir Lancelot:837-835-8257:474 Camelot Boulevard, Bath, WY 28356:5/13/69:24500
Jesse Neal:408-233-8971:45 Rose Terrace, San Francisco, CA 92303:2/3/36:25000
Zippy Pinhead:834-823-8319:2356 Bizarro Ave., Farmount, IL 84357:1/1/67:89500
Arthur Putie:923-835-8745:23 Wimp Lane, Kensington, DL 38758:8/31/69:126000
Popeye Sailor:156-454-3322:945 Bluto Street, Anywhere, USA 29358:3/19/35:22350
Jose Santiago:385-898-8357:38 Fife Way, Abilene, TX 39673:1/5/58:95600
Tommy Savage:408-724-0140:1222 Oxbow Court, Sunnyvale, CA 94087:5/19/66:34200
Yukio Takeshida:387-827-1095:13 Uno Lane, Ashville, NC 23556:7/1/29:57000
Vinh Tranh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900

1.把Jon’s的名字改成Jonathan.

[root@manager test6]# sed -n "s/Jon's/Jonathan/p" test6.txt

2.删除头三行

[root@manager test6]# cat -n test6.txt  | sed '1,3d'

3.显示5-10行

[root@manager test6]# cat -n test6.txt | sed -n '5,10p'
[root@manager test6]# cat -n test6.txt | sed '5,10!d'

4.删除包含Lane的行.

[root@manager test6]# sed '/Lane/d' test6.txt | grep Lane

5.显示所有生日在November-December之间的行

[root@manager test6]# sed -n '/:1[12]\//p' test6.txt

6.把三个星号(***)添加到也Fred开头的行

[root@manager test6]# grep Fred test6.txt | sed '/^Fred/s/^/***/'
[root@manager test6]# grep Fred test6.txt | sed 's/^Fred/***Fred/'

7.用JOSE HAS RETIRED取代包含Jose的行

[root@manager test6]# grep Jose test6.txt | sed '/Jose/s/.*/JOSE HAS RETIRED/'

8.把Popeye的生日改成11/14/46

[root@manager test6]# grep Popeye test6.txt | sed -r '/Popeye/s@[1]?[0-9]/[1-3]?[0-9]/[0-9][0-9]@11/14/46@'

9.删除所有空白行

[root@manager test6]# sed '/^$/d' test6.txt 
9. 替换命令
1. n 可以是1-512,表示第n次出现的情况进行替换
ababab
sed ‘s/ab/oo/2’ file
2. g 全局更改
apple apple apple
sed ‘s/apple/ooo/g’file

p 打印模式空间的内容(完成替换后)

apple apple apple
123 123 123
sed ‘s/apple/123/p’file.txt
只打印apple行 所以能用-n参数
3. w file 写入到一个文件file中(只保存替换后行)

sed  's/ab/OOO/w a.txt' test

& 用正则表达式匹配的内容进行替换

\n 回调参数 (前边的分组再拿回来)

&& 如

apple
123
apple

sed ‘s/apple/&&/’a.txt   &表示前边的正则表达式 2&代表输出2次

比如

this is linux 

sed ‘s/linux/& redhat/’file.txt

\n 如

$ cat test1
first:second
one:two
$ sed 's/\(.*\):\(.*\)/\2:\1/' test1
second:first
two:one
匹配交换第一第二个字符
sed -r‘s/(.)(.)/\2\1/’/etc/passwd
sed –r ‘s/(.)(.)(.*)/\2\1\3/’/etc/passwd

1.交换前两个单词

[root@manager test6]# sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\3\2\1\4/' test11.txt

2.将2.3字符换成xx

[root@manager test6]# sed -r 's/(.)(..)(.*)/\1XX\3/' test11.txt

3.将第一个单词和最后一个单词换位置

[root@manager test6]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)/\5\2\3\4\1/' test11.txt

4.将第一个字符和最后一个单词换位置

[root@manager test6]# sed -r 's/(.)(.*)([^a-Z]+)([a-Z]+)/\4\2\3\1/' test11.txt

如文件

apple banana	egg
一. apple banana egg
apple.Banana		egg
apple. Banana	egg
apple? Banana    egg
10. 删除

[address]d
删除模式空间的内容,同时改编脚本的控制流,执行这个命令后,在“空的”模式空间不再有命令执行。删除命令会导致读取新的输入行

sed ‘d;s’ 如果执行了d后边所有命令就不执行了,那么s做什么用?
sed ‘/a/d;s 这样如果匹配了a字符 就删除,否则就执行s 这样就构成了一个判断
sed ‘=’a.txt =显示行号

aaaaa
bbbbb
ccccc
dddd
sed '/c/d;=' test.txt

追加、插入和更改
[line-address]a text

aaaaa
bb xx bbb
ccccc
dddd
sed '/xx/a hello' test.txt

[line-address]i text

aaaaa
bb xx bbb
ccccc
dddd

sed '/xx/i hello' test.txt

[address]c text

aaaaa
bb xx bbb
ccccc
dddd

sed '/xx/c hello' test.txt

以上的操作都是将结果显示在屏幕上:怎么写入到文件

sed –i '/xx/c hello' test.txt
-i 直接对源文件做改变 注意文件inode会变化
1. 转换

[address]y/abc/xyz/

sed ‘y/abcdefghijklmnopqrstu…/ABCDEFGHIJKLMNOPQRS…/’a.txt
2. 打印

[address]p 用于输出模式空间的内容

·sed ‘’a.txt
sed ‘3p’a.txt

打印行号

[line-address]=
apple
123
apple

sed -n '/apple/{=;p}' test

下一步
[address]n
n命令输出模式空间的内容,然后读取输入的下一行,而不用返回脚本的顶端

test aa bb
test aa bb

sed ‘/test/{n;s/aa/xx}’test.txt

读和写文件 范例文件 file4.txt
[line-address]r file
[address]w file

sed -e '/<mail list>/r maillist' -e '/<mail list>/d' file4.txt
/MA$/w region.MA
/VA$/w region.VA
/CA$/w region.CA

如:
test aa bb
test aa bb

apple
banana
abc

sed ‘/banana/r aa.txt’ tt.txt

退出(速度更快)
[line-address]q
$ sed ‘100q’ test

测试:
for i in {1…100000}
do
echo $i >> num.txt
done

time sed –n ‘1,100p’num.txt
time sed ‘100q’num.txt

2. 高级sed 命令

高级命令分成3个组

1 处理多行模式空间(N、D、P)

2 采用保持空间来保存模式空间的内容并使它可用于后续的命令(H、h、G、g)

3 编写使用分支和条件指令的脚本来更改控制流(:、b、t)
高级脚本都做一件共同的事,那就是他们改变了执行或控制的流程顺序。

多行模式空间

1. 追加下一行

多行Next(N)命令通过读取新的输入行,并将它添加到模式空间的现有内容
之后来创建多行模式。

user1
123
user2
1234
user3
12345

将该文件 用户名,密码追加到一起

每两行合并sed ‘N;s/\n/:/’
[root@7-1 day2]# sed  -r 'N;  s/\n/:/g' t1.txt 

当三行合并一行的时候
[root@7-1 day2]# sed  -r 'N;N;  s/\n/:/g' t1.txt 
user1:123:456

2. 多行删除

D命令删除模式空间中直到第一个换行符的内容。它不会导致读入新的输入行,
相反,它返回到脚本的顶端,将这些指令应用与模式空间剩余的内容。

user1
123

M

user2
1234
W

user3
12345
M

sed '/^$/{N;/^\n$/D}' user.txt


/^$/{
N
/^\n$/D
}

多行删除命令完成工作的原因是,当遇到两个空行时,D命令只删除两个空行中的第一个。下一次遍历该脚本时,

这个空行将导致另一行被读入模式空间。

如果那行不为空,那么两行都输出,因此确保了输出一个空行。换句话说,当模式空间中有两个空行时,只有第一

个空行被删除。当一个空行后面跟有文本时,模式空间可以正常输出。

3. 多行打印

P命令输出多行模式空间的第一部分,直到第一个嵌入的换行符为止。在执行完脚本的最后一个命令之后,模式空

间的内容自动输出。

P命令经常出现在N命令之后和D命令之前。

这三个命令能建立一个输入、输出循环,用来维护两行模式空间,但是一次只输出一行。

这个循环的目的是只输出模式空间的第一行,然后返回到脚本的顶端将所有的命令应用于模式空间的第二行。

没有这个循环,当执行脚本中的最后一个命令时,模式空间中的这两行都将被输出。

删除文件倒数第二行

sed 'N;$!P;D' a.txt

删除文件最后两行

sed 'N;$!P;$!D;$d' a.txt
4. 包含那一行

模式空间是容纳当前输入行的缓冲区。还有一个成为保持空间(hode space)
的预留(set-aside)缓冲区。模式空间的内容可以复制到保持空间,而且保持
空间的内容也可以复制到模式空间。有一组命令用于在保持空间和模式空间之
间移动数据。保持空间用于临时存储。单独的命令不能寻址保持空间或者更改
它的内容。
保持空间最常见的用途是,当改变模式空间中的原始内容时,用于保留当
前输入行的副本。

模式空间 保持空间
默认换行符
h—覆盖 全部覆盖
H—追加-> 追加到换行符之后
g覆盖取回–
G追加取回—

例:

1111111
2222222
利用空间输出
2222222
11111111

sed ‘1h;1d;2G’test.txt

每行加一个空行?

11111
22222
33333
44444


反转

sed '1h;1d;2G;2h;2d;3G;3h;3d;4G' test17.txt
sed '1{h;d};2,3{G;h;d};4G' test17.txt 

sed '1!G;$!h;$!d' test17.txt 

大写转换
样本文件 file6.txt

find the Match statement
Consult the Get statement.
using the Read statement to retrieve data
将 the 和statement之间的单词转换成大写

脚本:changsrc

# capitalize statement names

/the .* statement/{
h
s/.*the \(.*\) statement.*/\1/
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
G
s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/
}

执行过程

h 将当前输入行复制到保持空间
Pattern Space: find the Match statement
Hold Space: find the Match statement

s/.*the \(.*\) statement.*/\1/ 取出将被替换的语句
Pattern Space: Match
Hold Space: find the Match statement
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
Pattern Space: MATCH
Hold Space: find the Match statement

G 将保持空间中的内容追加到模式空间
Pattern Space: MATCH\nfind the Match statement
Hold Space: find the Match statement

s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/ 替换并排序
Pattern Space: find the MATCH statement
Hold Space: find the Match statement


3. 练习

1,删除文件每行的第一个字符。

[root@manager zuoye]# sed 's/.//' aa.txt 

[root@manager zuoye]# sed -r 's/(.)(.*)/\2/' aa.txt

2,删除文件每行的第二个字符

[root@manager zuoye]# sed -r 's/(.)(.)(.*)/\1\3/' aa.txt*

3,删除文件每行的最后一个字符

[root@manager zuoye]# sed -r 's/(.*)(.)$/\1/' aa.txt

4,删除文件每行的倒数第二个字符

[root@manager zuoye]# sed -r 's/(.*)(.)(.)$/\1\3/' aa.txt 

5,删除文件每行的第二个单词

[root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)/\1\2/' aa.txt 

6,删除文件每行的倒数第二个单词

[root@manager zuoye]# sed -r 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)/\1\2\4\5/' aa.txt

7,删除文件每行的最后一个单词

[root@manager zuoye]# sed -r 's/(.*)([^a-Z]+)([a-Z]+)/\1\2/' aa.txt 

8,交换每行的第一个字符和第二个字符

[root@manager zuoye]# sed -r 's/(.)(.)(.*)/\2\1\3/' aa.txt 

9,交换每行的第一个字符和第二个单词。

[root@manager zuoye]# sed -r 's/(.)([a-Z]+)?([^a-Z]+)?([a-Z]+)/\4\2\3\1/' aa.txt

10,交换每行的第一个单词和最后一个单词

[root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)/\5\2\3\4\1/' aa.txt  

11,删除一个文件中所有的数字

[root@manager zuoye]# sed 's/[0-9]//g' aa.txt

12,删除每行开头的所有空格

[root@manager zuoye]# sed 's/^ *//g' aa.txt

13,用制表符替换文件中出现的所有空格

[root@manager zuoye]# sed 's/ /\t/g' aa.txt 

14,把所有大写字母用括号()括起来

[root@manager zuoye]# sed 's/[A-Z]/(&)/g' /etc/passwd

15,打印每行3次

[root@manager zuoye]# sed -n 'p;p;p' aa.txt 

16,隔行删除

[root@manager zuoye]# cat -n  /etc/passwd | sed 'n;d'。
[root@manager zuoye]# cat -n  /etc/passwd | sed '1d;n;d'
[root@manager zuoye]# cat -n  /etc/passwd | sed '0~2d'
[root@manager zuoye]# cat -n  /etc/passwd | sed '1~2d'

17,把文件从第22行到第33行复制到第56行后面

[root@manager zuoye]# cat -n /etc/passwd | sed '22h;23,33H;56G'

18,把文件从第22行到第33行移动到第56行后面

[root@manager zuoye]# cat -n /etc/passwd | sed '22{h;d};23,33{H;d};56G'

19,只显示每行的第一个单词

[root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)/\1/' aa.txt

20,打印每行的第一个单词和第三个单词

[root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1:\5/' aa.txt

21,将格式为 mm/yy/dd 的日期格式换成 mm;yy;dd

[root@manager zuoye]# echo "mm/yy/dd " | sed 's@/@:@g'

11. AWK

1. AWK简介

​ AWK是一种优良的文本处理工具。它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一。

这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的

首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、

数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实

际上 AWK 的确拥有自己的语言:AWK 程序设计语言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它

允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无

数其他的功能。

​ 最简单地说, AWK 是一种用于处理文本的编程语言工具。AWK 在很多方面类似于 shell 编程语言,尽管 AWK

具有完全属于其本身的语法。它的设计思想来源于 SNOBOL4 、sed 、Marc Rochkind设计的有效性语言、语言工

具 yacc 和 lex ,当然还从 C 语言中获取了一些优秀的思想。在最初创造 AWK 时,其目的是用于文本处理,并且

这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与

命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处

理下一行。

我们常用sed和awk相结合的方式处理文本sed|awk的方式能让我们的处理命令更快捷,提高工作效率

2. awk语法

awk [options] ‘commands’ files

option

-F 定义字段分隔符,默认的分隔符是连续的空格或制表符

aaaa   bbbb
aaa bb 
ccc       dd
awk{print $1}’a.txt


awk -F: ‘{print $1}’/etc/passwd

用$1,$2,$3等的顺序表示files中每行以间隔符号分隔的各列不同域.$0代表整行

awk{print $1,$2,$0}’a.txt

NF变量表示当前记录的字段数

awk -F: ‘{print NF}’/etc/passwd     返回字段数
awk -F: ‘{print $NF}’/etc/passwd    返回最后一个字段的内容

-v可以借用此方式从shell变量中引入
command
读前处理 行处理 读后处理

1.读前处理BEGIN{awk_cmd1;awk_cmd2}
awk 'BEGIN {print "hello,World"}'
awk 'BEGIN{print "start handle file"}{print}END{print"stop handle file"}' /etc/passwd

练习
先输出 开始处理文件
取当前系统所有用户的名字 uid 和 shell
最后输出 处理完毕

2.行处理:定址命令

定址方法: 正则,变量,比较和关系运算
正则需要用//包围起来

awk -F: '/root/{print}' /etc/passwd
awk -F: '$1~/root/{print}' /etc/passwd
awk -F: '$1!~/root/{print}' /etc/passwd
^ 行首
$ 行尾
. 除了换行符以外的任意单个字符
* 前导字符的零个或多个
.* 所有字符
[] 字符组内的任一字符
[^]对字符组内的每个字符取反(不匹配字符组内的每个字符)
^[^] 非字符组内的字符开头的行
[a-z] 小写字母
[A-Z] 大写字母
[a-Z] 小写和大写字母
[0-9] 数字
\< 单词头单词一般以空格或特殊字符做分隔,连续的字符串被当做单词
\> 单词尾

\ 转义字符
3. NR变量定址

NR 表示AWK读入的行数

FNR表示读入行所在文件中的行数

# awk '{print NR,FNR,$1}' file1 file2
1 1 aaaaa
2 2 bbbbb
3 3 ccccc
4 1 dddddd
5 2 eeeeee
6 3 ffffff

逻辑运算可直接引用域进行运算

== >= <= != > <
\# awk 'NR==1 {print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
4.命令{print $0}
5.读后处理END {awk_cmd1;awk_cmd2;}
cat 2.txt | head -2
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

awk –F”:”‘{print $1,$6}’2.txt | head -2
root /root
bin /bin

awk –F“:” ‘{print $1\t\t”$6}2.txt|head -2
root	/root
bin		/bin

awk –F”:”	‘BEGIN{print “用户名\t\t家目录”}{print $1\t\t”$6}’2.txt| head -2

例2:cat 1.txt

mona 70 77 85 83 70 89
john 85 92 78 94 88 91
andrea 89 90 85 94 90 95
jasper 84 88 80 92 84 82
dunce 6 80 60 60 61 62
ellis 5 98 89 96 96 92


awk 'BEGIN{print "\t\t某某班14暑假成绩";print "学员\t数学\t语文\t英语\t化学\t物理\t历史"}{print $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7}END{print "年级排名请查询数据库"}' test3.txt l

awk 'BEGIN{OFS="\t";print "\t\t某某班14暑假成绩";print "学 员\t数学\t语文\t英语\t化学\t物理\t历史"}{print $1,$2,$3,$4,$5,$6,$7}END{print "年级排名请查询数据库"}' test3.txt

[root@7-1 day3]# awk 'BEGIN{print "\t\t某某班级成绩单\n姓名\t语文\t数学\t英语\t物理\t化 学\t生物"}{print $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7}' b.txt 
		某某班级成绩单
姓名	  语文 数学	英语	物理	化学	生物
mona	70	 77	 85	 83	   70	89
john	85	 92	 78	 94	   88	91
andrea	89	90	 85	 94	   90	95
jasper	84	88	 80	 92	   84	82
dunce	6	80	 60	 60	   61	62
ellis	5	98	 89	 96	   96	92
awk{print $0}’1.txt
awk$2~/6/{print $0}’1.txt
awk$2>=6{print $0}’1.txt

3. 操作符

1. 赋值= ++ – += -= /= *=
++ Add 1 to variable.
awk 'BEGIN{a=1;a++;print a}'  打印值为2
awk 'BEGIN{a=1;++a;print a}'  打印值为2 先加1在执行命令
awk 'BEGIN{a=1;print a++;print a}' 先执行命令然后a+1
a=1命令先执行a还=1,最后在打印a=2

-- Subtract 1 from variable. awk '
BEGIN{a=1;a--;print a}' 打印值为0

+= Assign result of addition.
awk 'BEGIN{a=1;b=a+5;print b}'  给b赋值
awk 'BEGIN{a=1;a=a+5;print a}'  给自己赋值
awk 'BEGIN{a=1;a+=5;print a}'  上条命令简化写法

-= Assign result of subtraction.
awk 'BEGIN{a=1;a-=5;print a}'  a-5在赋值给a 以下相同
awk 'BEGIN{a=1;a-=5.2;print a}' 支持小数运算
*= Assign result of multiplication.
/= Assign result of division.
%= Assign result of modulo.
^= Assign result of exponentiation


|| Logical OR 逻辑 两边任意一边成立
&& Logical AND 逻辑与 两边成立 前边如果假值后边就不做了
! Logical NOT 逻辑取反 原本真值变成假值.

awk '$1~/root/||NR>40{print}' /etc/passwd
awk '$1~/root/&&NR<2{print}' /etc/passwd
匹配正则或不匹配,正则需要用/正则/ 包围住
!~

关系比较字符串时要把字符串用双引号引起来
< <= > >= != ==

2. 字段引用

$ 字段引用需要加$,而变量引用直接用变量名取
运算符+ - * / % ++ –

3. 转义序列
\ \自身
\$ 转义$
\t 制表符
\b 退格符
\r 回车符
\n 换行符
\c 取消换行
4. awk引用shell变量
a=root
awk –v var=$a –F“:” ’$1==var{print $0}’ /etc/passwd
5. 内置变量
FS 定义字段分隔符,默认为一个空格

OFS 输出的字段分隔符,默认为一个空格

awk 'BEGIN{ FS=":";OFS="-" }{ print $1,$3,$5 }' /etc/passwd  | head -2
awk 'BEGIN{ FS=":";OFS="-" }{ print $1”@@”$3”##”$5 }' /etc/passwd  | head -2  自己定义

RS 记录分隔符,默认为一个换行符

head -2 /etc/passwd | awk 'BEGIN{ RS=":"}{print}'

ORS 输出的记录分隔符,默认为一个换行符

head -2 /etc/passwd | awk 'BEGIN{ ORS="-"}{print}'

NR 行数(如两个文件一个5行 1个10行 输出为15行)

awk  '{print NR}' aa.txt cc.txt

FNR 行数,多文件操作时会重新排序(如两个文件一个5行,一个10行 输出为5 10) awk  '{print FNR}' aa.txt 
cc.txt

NF 输出当前输入记录的编号(字段的个数)
aaaa bbb ccc
cccc bbb
aaa ccc bb  nn

awk '{ print NF}' aa.txt

FILENAME 文件名

ARGC 命令行参数个数

ARGV 命令行参数排列

ENVIRON 输出系统环境变量

例子

cat awk.txt
aaa#123
asdf:234
haha:456

awk –F’#’ ’{print NR,$0,NF,FILENAME }’awk.txt
1 aaaa#123 2 awk.sh
2 asdf:234 1 awk.sh
3 haha:456 1 awk.sh
4  0 awk.sh

awk -F"#" '{ print ARGC,ARGV[0],ARGV[1]}' awk.sh.txt
2 awk awk.sh.txt
2 awk awk.sh.txt
2 awk awk.sh.txt
2 awk awk.sh.txt

awk -F"#" '{ print NR,$0,NF,$1,$2 }' awk.sh.txt
1 aaaa#123 2 aaaa 123
2 asdf:234 1 asdf:234
3 haha:456 1 haha:456
4  0

awk 'BEGIN{print ENVIRON["USER"]}'

4. 练习题

1.打印uid在30~40范围内的用户名

awk -F: '$3>=30&&$3<=40{print $1,$3}' /etc/passwd

2.打印第5-10行的行号和用户名

awk -F: 'NR>=5&&NR<=10{print $1,NR}' /etc/passwd

3 .打印奇数行

awk -F: 'NR%2==1{print NR,$0}' /etc/passwd

4.打印偶数行

awk -F: 'NR%2==0{print NR,$0}' /etc/passwd

5.打印字段数大于5的行

awk -F: 'NF>5{print $0}' /etc/passwd

6.打印UID不等于GID的用户名

awk -F: '$3!=$4{print $0}' /etc/passwd

7.打印1…100以内的7的倍数和包含7的数

seq 1 100 | awk '$1~/7/||$1%7==0{print $1}'

8.计算UID相加的总和;计算GID相加的总和

awk -F: '{uid+=$3;gid+=$4}END{print uid;print gid}' /etc/passwd

9.计算VSZ和RSS各自的和 并以M单位显示

ps aux|awk 'NR>1{vsz+=$5;rss+=$6}END{print vsz/1024"M";print rss/1024"M"}'

5. 流程控制

1. 分支结构
1. if (条件) 动作

若有多个动作,则要用大括号将动作体包含起来if (条件) {动作1;动作2}

# awk -F : '{if ($1 == "root") print $1}' /etc/passwd
# awk -F: '{if ($1 == "root") {print $1;print $6} }' /etc/passwd
2. if(条件1)

if(条件1)

​ 动作1
else
​ 动作2

# awk -F: '{if ($1 == "root"){print $1}else print $6}' /etc/passwd
# awk -F: '{if ($1 == "root") print $1;else print $6}' /etc/passwd

上面两个命令是等价的,要么用分号隔开,表示第一个动作体的结束,要么将动作体用大括号定位范围

3. if(条件1)

if (条件1)
动作1
else if(条件2)
动作2
else if(条件3)
动作3
else
动作

awk -F: '{if ($1 == "root") print $1;else if ($1 == "seker") print $6;else if ($1 == "zorro") print $7;else printNR}' /etc/passwd
4. 读前处理和读后处理
# awk -F: 'BEGIN {print NR,NF}' /etc/passwd
0 0
# awk -F: 'END {print NR,NF}' /etc/passwd
46 7
# awk -F: 'BEGIN{i=1} {i++} END {print i}' /etc/passwd
47

练习:

1.找出普通用户的用户名并统计数量

[root@manager test7]# awk -F: '{if($3>=500) sum+=1}END{print sum}' /etc/passwd

2.将系统用户按UID分组标记 0 admin; 1-499 sysuser; 500+ users

用户名 uid 权限
root 0 admin
ftp 21 sysuser
robin 500 users

[root@manager test7]# awk 'BEGIN{FS=":";OFS="\t";print "用户名\tUID\t权限"}{if($3==0)print $1,$3,"admin";else if($3<500)print $1,$3,"sysusers";else print $1,$3,"users"}' /etc/passwd

awk 'BEGIN{OFS="\t";print "名字\t语文\t数学\t英语\t历史\t物理\t生物\t总成绩\t平均\t评价"}{sum=$2+$3+$4+$5+$6+$7;if(sum/6>=90)print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"优秀";else if(sum/6>=80)print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"良好";else if(sum/6>=70)print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"一般";else print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"烂"}END{print "某某班级期中成绩"}' chengji.txt
5. 循环语句

while(条件) {

​ 动作

​ 条件运算

}

awk -F: '{while($3<3) {print $3,$1;$3++}}' /etc/passwd

BEGIN块可以独立使用,不需要引入文件

 awk 'BEGIN{i=1;while(i<100) {print i;i++}}'

练习

1.打印100以内的偶数

awk 'BEGIN{i=1;while(i<100){if(i%2==0)print i;i++}}'


x=1
do {
动作1
x++
} while (x<5)
# awk 'BEGIN{i=5;do{print i;i++}while(i<10)}'
# awk 'BEGIN{i=5;do{print i;i++}while(i<1)}'


[root@7-1 day3]# awk 'BEGIN{i=1;while(i<=100){if(i%2==0){sum+=i;}i++}print sum}'
2550

for(预置;条件;递增) {
动作
}

# awk 'BEGIN {for (x=1;x<=4;x++) print x }'

[root@7-1 day3]# awk 'BEGIN{for (i=1;i<=100;i++)if(i%2==0){sum+=i}print sum}'
2550

练习
逆序输出每个字段
达到这样既可

/bin/bash
	/root
	root
	0
	0
	x
	root

awk -F: ‘BEGIN{printf “%-15s %-15s %-15s\n”,“用户名”,“UID”,“权限”}{if ($3==0) printf “%-18s %-15s %-15s\n”,$1,$3,“admin”;else if($3<500) printf “%-18s %-15s %-15s\n”,$1,$3,“sysuser”;else printf “%-18s %-15s %-15s\n”,$1,$3,“users”}’ /etc/passw

6. 跳转语句

break 跳出循环

# awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) break;print x }}'
1
2

continue 在达到循环底部之前终止当前循环从新开始下一次循环

# awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) continue;print x }}'
1
2
4

next 读入下一行同时返回脚本顶部这样可以避免对当前行执行其他操作

# awk -F: 'NR > 5 {next} {print $1} END {print NR}' /etc/passwd
root
bin
daemon
adm
lp

cat -b u.txt

1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 news:x:9:13:news:/etc/news:

awk -F: 'BEGIN{i=1}NR>5 {next}{print i++}END{print NR}' u.txt
1
2
3
4
5
10

awk -F: 'BEGIN{i=1}NR>5 {exit}{print i++}END{print NR}' u.txt
1
2
3
4
5

6. 数组

1. 自定义数组
# awk 'BEGIN {ary[1]="seker";ary[2]="zorro";print ary[1],ary[2]}'
seker zorro

# awk 'BEGIN {ary[1]="seker";ary[2]="zorro";for(i in ary) print ary[i]}'
seker
zorro
2. 循环产生数组和取出数组
# awk 'BEGIN{n=5;for (i=1;i<=n;i++) ary[i]=i+100;for(m in ary) print m,ary[m]}'
4 104
5 105
1 101
2 102
3 103

awk -F: '{ary[NR]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail


awk -F: '{ary[$3]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd
10 uucp
11 operator
12 games
13 gopher
14 ftp
32 rpc
37 rpm
3. 利用数组实现行列互换
[root@manager ~]# cat aa.txt 
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5

1 1 1 1 1 
2 2 2 2 2 
3 3 3 3 3 
4 4 4 4 4 
5 5 5 5 5

[root@manager test7]# awk '{for(i=1;i<=NF;i++) ary[NR,i]=$i}END{for(j=1;j<=NF;j++){for(l=1;l<=NR;l++)printf ary[l,j]" ";printf "\n"}}' kk.txt

7. awk的内置函数

1. 算数函数
1. sqrt函数(求平方根)
[root@manager ~]# awk 'BEGIN{x=sqrt(100);print x}'
10

[root@manager ~]# awk 'BEGIN{x=int(3.14);print x}'
3
[root@manager ~]# awk 'BEGIN{x=int(3.88);print x}'
3

2. rand函数

rand函数(内置函数 srand 使用参数awk 'BEGIN{x=rand();print x}'作为随机数种子。当参数缺省的时候,使用当

前时间作为随机数种子。)

[root@manager ~]# awk 'BEGIN{x=rand();print x}'
0.237788
3. srand函数

srand函数(内置函数 rand 的伪随机函数,其返回值范围为 0 >= result <= 1。在实际使用时,一般先使用 srand

函数生成随机数种子,然后再使用 rand 函数生成随机数。否则每次得到的值会一样。)

[root@manager ~]# awk 'BEGIN{srand();x=int(100*rand());print x}'
64
[root@manager ~]# awk 'BEGIN{srand();x=int(100*rand());print x}'
32
[root@manager ~]# awk 'BEGIN{srand();x=int(100*rand());print x}'
60

2. 字符串函数
1. sub和gsub函数使用(替换字符)
[root@manager ~]# awk 'BEGIN{info="this is a test2010test2010test!";sub(2010,"!",info);print info}'
this is a test!test2010test!

[root@manager ~]# awk 'BEGIN{info="this is a test2010test2010test!";gsub(2010,"!",info);print info}'
this is a test!test!test!
2. index函数(查找字符)
[root@manager ~]# awk 'BEGIN{info="this is test2010test!";print index(info,"test")?"ok":"not found";}'
ok
3. length函数(计算长度)
[root@manager ~]# awk 'BEGIN{info="hello";print length(info)}'
5
4. substr函数(截取字符串)
[root@manager ~]# awk 'BEGIN{info="hello world";print substr(info,4,10)}'
lo world
5. match函数(正则匹配查找)
[root@manager ~]# awk 'BEGIN{info="hello 2016world";print match(info,/[0-9]+/)?"ok":"none";}'
ok
6. split函数(字符分割)
[root@manager ~]# awk 'BEGIN{info="hello world";split(info,test);print length(test);for(k in test){print k,test[k];}}'
2
1 hello
2 world
3. 一般函数
函数说明
close( Expression )用同一个带字符串值的 Expression 参数来关闭由 print 或 printf 语句打开的或调用 getline 函数打开的文件或管道。如果文件或管道成功关闭,则返回 0;其它情况下返回非零值。如果打算写一个文件,并稍后在同一个程序中读取文件,则 close 语句是必需的。
system(Command )执行 Command 参数指定的命令,并返回退出状态。等同于 system 子例程。
Expression | getline [ Variable ]从来自 Expression 参数指定的命令的输出中通过管道传送的流中读取一个输入记录,并将该记录的值指定给 Variable 参数指定的变量。如果当前未打开将 Expression 参数的值作为其命令名称的流,则创建流。创建的流等同于调用 popen 子例程,此时 Command 参数取 Expression 参数的值且 Mode 参数设置为一个是 r 的值。只要流保留打开且 Expression 参数求得同一个字符串,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
getline [ Variable ] < Expression从 Expression 参数指定的文件读取输入的下一个记录,并将 Variable 参数指定的变量设置为该记录的值。只要流保留打开且 Expression 参数对同一个字符串求值,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
getline [ Variable ]将 Variable 参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定 Variable 参数,则 $0 记录变量设置为该记录的值,还将设置 NF、NR 和 FNR 特殊变量。
1. close函数
[root@manager ~]# awk 'BEGIN{while("head -5 /etc/passwd"|getline){print $0;};close("/etc/passwd");}'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
2. getline函数
[root@manager ~]#  awk 'BEGIN{while(getline < "/etc/passwd"){print $0;};close("/etc/passwd");}'


[root@manager ~]#  awk 'BEGIN{print "Enter your name:";getline name;print name;}'
Enter your name:
robin
robin
[root@manager ~]#  awk 'BEGIN{printf "Enter your name:";getline name;print name;}'
Enter your name:robin
robin

[root@manager test7]# awk -F: 'BEGIN{printf "输入用户名: ";getline name;while(getline < "/etc/passwd"){if($1==name) print $0}}'


3. system函数
[root@manager ~]#  awk 'BEGIN{b=system("ls -l /root");print b;}'
总用量 20
-rw-r--r--  1 root root  135 9月  18 16:14 aa.txt
-rw-------. 1 root root  905 9月   9 06:30 anaconda-ks.cfg
-rw-r--r--. 1 root root 8003 9月   9 06:30 install.log
-rw-r--r--. 1 root root 3384 9月   9 06:30 install.log.syslog
0
[root@manager test7]# awk -F: 'BEGIN{x=system("id robin &>/dev/null");if(x==0){while(getline < "/etc/passwd")if($1=="robin")print $1,$6}}'
robin /home/robin
4. 时间函数
点击这里点击这里
函数名说明
mktime( YYYY MM DD HH MM SS[ DST])生成时间格式
strftime([format [, timestamp]])格式化时间输出,将时间戳转为时间字符串 具体格式,见下表.
systime()得到时间戳,返回从1970年1月1日开始到当前时间(不计闰年)的整秒数
1. 创建时间格式
[root@manager ~]# awk 'BEGIN{tstamp=mktime("2001 01 01 12 12 12");print strftime("%c",tstamp);}'
2001年01月01日 星期一 12时12分12秒

[root@manager ~]#  awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=mktime("2001 02 01 0 0 0");print tstamp2-tstamp1;}'
2634468


[root@manager ~]# awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=systime();print tstamp2-tstamp1;}' 
495876393


2. strftime日期和时间格式说明符
格式描述
%a星期几的缩写(Sun)
%A星期几的完整写法(Sunday)
%b月名的缩写(Oct)
%B月名的完整写法(October)
%c本地日期和时间
%d十进制日期
%D日期 08/20/99
%e日期,如果只有一位会补上一个空格
%H用十进制表示24小时格式的小时
%I用十进制表示12小时格式的小时
%j从1月1日起一年中的第几天
%m十进制表示的月份
%M十进制表示的分钟
%p12小时表示法(AM/PM)
%S十进制表示的秒
%U十进制表示的一年中的第几个星期(星期天作为一个星期的开始)
%w十进制表示的星期几(星期天是0)
%W十进制表示的一年中的第几个星期(星期一作为一个星期的开始)
%x重新设置本地日期(08/20/99)
%X重新设置本地时间(12:00:00)
%y两位数字表示的年(99)
%Y当前月份
%Z时区(PDT)
%%百分号(%)
5. printf函数

​ 是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。在编写程序时经常会用到此函数。printf()函

数的调用格式为:

%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x, %X 无符号以十六进制表示的整数
%o 无符号以八进制表示的整数
%g 自动选择合适的表示法
\n 换行
\f 清屏并换页
\r 回车
\t Tab符
\xhh 表示一个ASCII码用16进表示,其中hh是1到2个16进制数

输出样式
%s是字符类型,%d数值类型

​ printf默认是不输出换行的所以要加\n

​ 10和7是偏移量

​ 默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充

​ 注意:格式与输出列之间要有逗号

[root@manager ~]# awk 'BEGIN{a=16;printf "%-10o\n",a}'
20


8. 练习

1.使用awk打印一个用星号组成金字塔

2.使用awk打印99乘法表

3.输出100-999
1-9 0-9 0-9

4.开两个虚拟机,定时(10分钟)将虚拟机的httpd日志收集到本机,提取,这些httpd日志的 ip 访问时间 浏览器 保存到文件

练习1答案
\1. awk -F: '$3>=30&&$3<=40 {print NR, $1}' passwd
\2. awk -F: 'NR>=5&&NR<=10 {print NR, $1}' passwd
\3. awk -F: 'NR%2!=0 {print}' passwd
\4. awk -F: 'NR%2==0 {print}' passwd
\5. awk -F: 'NF>5 {print NR}' passwd
\6. awk -F: '$3!=$4 {print $3,$4}' passwd
\7. seq 100 | awk '$0%7==0 || $0 ~/7/ {print $0}' | head -3
\8. awk -F: 'BEGIN{i=0}{sum+=$3;gsum+=$4;i++}END{print i;print sum;print gsum}' /etc/passwd
\9. ps aux | awk 'BEGIN{i=0}NR>=2{vsum+=$5;rsum+=$6;i++}END{print vsum/1024"M";print rsum/1024"M";print i}'
练习2:
练习找出普通用户的用户名并统计数量
awk -F: 'BEGIN{i=0} $3>=500 {print $1;i++} END {print i}' /etc/passwd
awk -F: '{if($3==0) print $1"\t"$3"\t""admin";else if($3>=1&&$3<500) print $1,$3,"sysuser";else print $1,$3,"user"}' /etc/passwd
练习打印100以内的偶数
\# awk 'BEGIN{i=1;while(i<100) {if (i%2==0) print i;i++}}'

逆序输出每个字段
	达到这样既可
	/bin/bash
	/root
	root
	0
	0
	x
	root


	# awk -F: '{for (x=NF;x>0;x--) print $x}' /etc/passwd

输出样式
	%s是字符类型,%d数值类型
	printf默认是不输出换行的所以要加\n
	10和7是偏移量
	默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充
	注意:格式与输出列之间要有逗号
	# awk -F: '{printf "%-10s %-10d %s\n",$1,$3,$7}' /etc/passwd

继续解决上一个试做题的格式问题
	# awk -F: '/bash$/{for (x=NF;x>0;x--) printf "%-13s",$x;printf "\n"}' /etc/passwd



使用嵌套的for循环,打印100-999之间的数,个十百位分别用一个for来打印
	# awk 'BEGIN{OFS="";for (i=1;i<=9;i++) {for (j=0;j<=9;j++) {for (n=0;n<=9;n++) print i,j,n}}}'
    打印乘法口诀表
	# cat 99.sh 
	#!/bin/bash
	awk 'BEGIN{
		for(i=1;i<10;i++)
		{
			for(j=1;j<=i;j++)
				printf "%d*%d=%d ",j,i,j*i
			print
		}	

​	}'# 

​    打印金字塔
​	# cat jin.sh #!/bin/bashawk 'BEGIN{
​		num=5
​		for(i=1;i<=num;i++)
​		{	
​			for (n=1;n<=num-i;n++)
​				printf "%s"," "
​			for (j=1;j<=2*i-1;j++)
​		   		printf "%s","*"
​			print
​		}
​	}'



[root@manager ~]# awk '{for(i=1;i<=NF;i++) ary[NR,i]=$i}END{for(j=1;j<=NF;j++){for(k=1;k<=NR;k++)printf ary[k,j]" ";printf "\n"}}' aa.txt 
1 1 1 1 1 
2 2 2 2 2 
3 3 3 3 3 
4 4 4 4 4 
5 5 5 5 5 
[root@manager ~]# cat aa.txt 
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

脑子是空的啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值