现在我们使用的操作系统(windows,Mac OS,Android,iOS等)都是带图形界面的,简单直观,容易上手,对于专业用户(程序员,网管等)和普通用户都非常适用;计算机的普及离不开图形界面。
然而计算机的早期并没有图形界面,我们只能通过一个一个命令来控制计算机,这些命令有成百上千之多,且不说记住这些命令是十分困难,每天面对没有任何色彩的黑屏本身就是一件枯燥的事情;这个时候的计算机还远远谈不上炫酷和普及,只有专业人士才能使用。
对于图形界面,用户只需要点击某个图标就能启动某个程序;对于命令行,用户输入某个程序的名字(可以看做一个命令)就能启动某个程序。这两者的基本过程都是类似的,都需要查找程序在硬盘上的安装位置,然后将他们加载到内存运行。换句话说,图形界面和命令行要达到的目的是一样的,都是让用户控制计算机。然而,真正能够控制计算机硬件(CPU 内存 显示器)的只有操作系统内核(kernel),图形界面和命令行只是架设在用户和内核之间的一座桥梁。
由于安全 复杂 繁琐的原因,用户不能直接接触内核(也没有必要),需要另外开发一个程序,让用户直接使用这个程序;该程序的作用就是就接收用户的操作(点击图标 输入命令),并进行简单的处理,然后再传递给内核。如此一来,用户和内核之间就多了一层"代理",这层"代理"既简化了用户的操作,也保护了内核。
用户界面和命令行就是这个另外开发的程序,就是这层代理"代理"。在linux下,这个命令行就叫做shell
Shell Script,Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次
性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用
其他编程程序编辑的程序效率更高,毕竟它使用了Linux/Unix下的命令。
换一种说法也就是,shell script是利用shell的功能所写的一个程序,这个程序是使用纯文本文件,将一些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 都非常合适
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。
shell 脚本的格式
Shell 脚本文件的名称可以任意,但为了避免被误以为是普通文件,建议将 .sh 后缀加上,以表示是一个脚本文件。
shell 脚本中一般会出现三种不同的元素:
第一行的脚本声明(#!)用来告诉系统使用哪种 Shell 解释器来执行该脚本;
第二行的注释信息(#)是对脚本功能和某些命令的介绍信息,使得自己或他人在日后看到这个脚本内容时,可以快速知道该脚本的作用或一些警告信息;
第三、四行的可执行语句也就是我们平时执行的 Linux 命令了。
shell是什么呢?确切一点说,Shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解
释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用Shell来启动、
挂起、停止甚3至是编写一些程序。 Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是
一种命令语言,又是一种程序设计语言(就是你所说的shell脚本)。作为命令语言,它互动式地解释和执行用户输入
的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高阶语言中才具有的控制结构,包括循环
和分支。它虽然不是 Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、创建文档并以并行
的方式协调各个程序的运行。
交互式模式就是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
给.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告诉系统,就在当前目录找。
运行这种方式是,直接运行解释器,其参数就是shell脚本的文件名 如
/bin/sh test.sh
/bin/php test.php
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
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
1 求/etc/passwd文件第20行内容
[root@manager test1]# cat -n /etc/passwd | head -20 | tail -1
rev,tac命令
rev左右颠倒
tac上下颠倒
常用选项
-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
*/10 * * * * 脚本|命令
当在前台运行某个作业时,终端被该作业占据;而在后台运行作业时,它不会占据终端。
xclock -update 1 & 后台运行
关闭终端程序也会关闭
如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用 nohup命令。该命令可以在你退出帐户之后继续运行相应的进程。 nohup就是不挂起的意思( nohang up)。
该命令的一般形式为
nohup command &
nohup xclock -update 1 &
* 可以显示所有的匹配内容
? 匹配字符(可以是未知的字符)
[...]和[!...] [a-z] [0-9] [!a12d]
{..}
双引号和单引号的区别
单引号
-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十进制整数
可以使用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
管道(Pipe)实际是用于进程间通信的一段共享内存. 创建管道的进程称为管道服务器,连接到一个管道的进程为
管道客户机
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 <
文件描述符:进程连接到文件时,获得的一个标记.当进程操作文件时,首先打开文件 获得打开文件的一个状态,给它
一个标记 成为文件描述符
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 <
\> n
\>
\> +200M
\> w
\> EOF
<<<here string 后边跟字符串 直接交给文本 如:
cat >x.txt <<<asdadad
cat x.txt
\> >> < << <<<
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命令既可以让结果输出在文件里面也可以在终端中显示。
[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
[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
--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
[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
• 大小写转换。
• 去除控制字符。
• 删除空行。
[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
-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
显示末尾文件名
[root@manager ~]# basename /var/log/messages
messages
[root@manager ~]# basename /var/log/
log
[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
有匹配域
[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
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" " - - - - - -
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定向到那条命令然后再执行。
[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"
2016年 10月 15日 星期六 10:10:10 CST
[root@manager tmp]# date +%Y-%m-%d-%H-%M-%S
2016-09-20-13-58-09
[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 日志位置
整数
[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
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
写一个 一键配置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
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(以及命令的回顾)
环境变量是一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。例如path,当要求
系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中
指定的路径去找。用户通过设置环境变量,来更好的运行进程
环境变量:系统在启动过程中预先指定好的一系列的变量.比如当前用户是谁 当前shell是什么 当前用户的家目录在
什么位置等等
预定义变量:系统预定义好的 和进程名称 进程编号 进程参数 进程返回值相关
位置变量和命令行参数相关
自定义变量(用户自己定义的变量)
环境变量 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
$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 ~]#
位置变量: 和命令行参数相关 (命令后跟的参数$1-$9)
自定义变量:当用户变量不够用时,自定义的变量
如下测试脚本
#!/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
在定义变量时,变量名不加美元符号($,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下目录的文件名循环出来
使用一个定义过的变量,只要在变量名前面加上美元符号($)即可:
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",使用变量的时候才加美元符($)。
使用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
使用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
函数库:将常用的变量定义到一个文件里 直接加载这个文件 就不用重复定义变量了
如系统中的确定与失败
子进程定义的变量能否被父进程集成
nologin shell 和 login shell
/etc/bashrc
/etc/bashrc
~/.bashrc
~/.bash_profile
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 ))
通配符是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
语法: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手册进行查看,具体作用全部都有。
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
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
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。
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.判断自己是否为重复运行脚本,如果为重复运行的脚本则自动退出(同一时间该脚本只有一个实例运行)
如下脚本
#!/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
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
#?
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
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)
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
函数也可以让我们死机 如下
){ :& };:
可以看我们的系统服务启动脚本了
#!/bin/bash
a=123
func(){
echo $a
}
func # 调用
#!/bin/bash
func(){
a=123
}
func
echo $a
#!/bin/bash
func(){
local a=123
echo "in func"
echo $a
}
func
echo "out of func"
echo $a
#!/bin/bash
sum(){
echo $(($1+$2))
}
sum 10 20
#!/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
提取主机名 函数
提取ip地址 函数 (多网卡)
检查自己主机启动什么服务的 函数
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)
(可以用if实现 这是另外一种方式)
若 parameter 为空或未设置,则用 word 代替 parameter 进行替换,parameter 的值不变
# a=1
# unset b
# a=${b:-3}
# echo $a
# a=1
# b=2
# a=${b:-3}
# echo $a
# echo $b
若 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
若 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
若 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
shell的数组分为普通数组和关联数组
只能以数字作为数组
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
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
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
tput 可以操作光标,定位光标
tput sc 保存光标位置
tput rc 返回光标位置
tput cols 读取列数
tput lines 读取行数
tput cup lines cols
tput civis # 光标不可见
tput cnorm # 光标可见
#!/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
脚本代码如下
#!/usr/bin/expect
set timeout 30
spawn ssh -l username 192.168.1.1
expect "password:"
send "ispass\r"
interact
##############################################
这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。
注意:这一行需要在脚本的第一行。
基本上认识英文的都知道这是设置超时时间的,现在你只要记住他的计时单位是:秒
spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。所以不要用 “which spawn“之类的命令去找spawn命令。好比windows里的dir就是一个内部命令,这个命令由shell自带,你无法找到一个dir.com 或 dir.exe 的可执行文件。
它主要的功能是给ssh运行进程加个壳,用来传递交互指令。
这里的expect也是expect的一个内部命令,有点晕吧,expect的shell命令和内部命令是一样的,但不是一个功能,习惯就好了。这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是前面设置的30秒
这里就是执行交互动作,与手工输入密码的动作等效。
温馨提示: 命令字符串结尾别忘记加上 “\r”,如果出现异常等待的状态可以核查一下。
执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。如果你只是登录过去执行一段命令就退出,可改为[expect eof]
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
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}'
正则表达式分为三类(man grep可以看到,分别是basic RegExs,extended RegExs,perl RegExs)
1、基本的正则表达式(Basic Regular Expression 又叫 Basic RegEx 简称 BREs)
2、扩展的正则表达式(Extended Regular Expression 又叫 Extended RegEx 简称 EREs)
3、Perl 的正则表达式(Perl Regular Expression 又叫 Perl RegEx 简称 PREs)
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 RegEx | Extended RegEx | python RegEx | Perl regEx |
---|---|---|---|---|---|
转义 | \ | \ | \ | \ | |
^ | 匹配行首,例如’^dog’匹配以字符串dog开头的行(注意:awk 指令中,’^'则是匹配字符串的开始) | ^ | ^ | ^ | ^ |
$ | 匹配行尾,例如:’^、dog ′ 匹 配 以 字 符 串 d o g 为 结 尾 的 行 ( 注 意 : a w k 指 令 中 , ′ '匹配以字符串 dog 为结尾的行(注意:awk 指令中,' ′匹配以字符串dog为结尾的行(注意:awk指令中,′’则是匹配字符串的结尾) | $ | $ | $ | $ |
^$ | 匹配空行 | ^$ | ^$ | ^$ | ^$ |
^string$ | 匹配行,例如:’^dog$'匹配只含一个字符串 dog 的行 | ^string$ | ^string$ | ^string$ | ^string$ |
< | 匹配单词,例如:’< |
< |
不支持 |
不支持(但可以使用\b来匹配单词,例如:’\bfrog’) |
|
> | 匹配单词,例如:‘frog>’(等价于’frog\b '),匹配以 frog 结尾的单词 | > | > | 不支持 | 不支持(但可以使用\b来匹配单词,例如:‘frog\b’) |
匹配一个单词或者一个特定字符,例如:’ |
不支持 | 不支持(但可以使用\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|y | x|y | x|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]
正则表达式及字符处理
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/
sed文档
元字符
. 匹配除换行符之外的任意单个字符,awk中可以匹配换行符
例:
abc adc aec
a.c
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
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 多个空格的行
\ 转义字符
如
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全局替换
a
ab
abb
abbb
sed 's/abb*/x/' a.txt
sed -r 's/ab+/x/' a.txt
y
yes
Y
Yes
sed -r 's/[yY](es)?/x/' a.txt
() 替换方案 对正则表达式分组
company
companies
compan(y|ies)
[abc] (a|b|c) 某些情况下一样 还有分组功能后边会用到
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
sed ‘s/元字符在这里起作用匹配/±|则不再起元字符作用/’
编写sed脚本 要求如下
原始 完成后
apple banana
banana orange
一条命令完成
是不是我们想的结果?
为什么产生上边的问题:
首先sed在运行中会维护一段内存空间,这段内存空间称为模式空间:
模式空间存储被替换的文件,默认是按行为单位
如上文件读取过程
首先进入模式空间s-----apple 替换为banana
在执行s-----banana 替换为orange
结果apple被替换成orange 没有-n参数 输出终端上
第二条进入模式空间 第一条命令匹配不上,第二条匹配 banana
被替换为orange
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
删除所有的行 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
.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
文件: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
ababab
sed ‘s/ab/oo/2’ file
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参数
如
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
[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会变化
[address]y/abc/xyz/
sed ‘y/abcdefghijklmnopqrstu…/ABCDEFGHIJKLMNOPQRS…/’a.txt
[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 '//r maillist' -e '//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
高级命令分成3个组
1 处理多行模式空间(N、D、P)
2 采用保持空间来保存模式空间的内容并使它可用于后续的命令(H、h、G、g)
3 编写使用分支和条件指令的脚本来更改控制流(:、b、t)
高级脚本都做一件共同的事,那就是他们改变了执行或控制的流程顺序。
多行模式空间
多行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
D命令删除模式空间中直到第一个换行符的内容。它不会导致读入新的输入行,
相反,它返回到脚本的顶端,将这些指令应用与模式空间剩余的内容。
user1
123
M
user2
1234
W
user3
12345
M
sed '/^$/{N;/^\n$/D}' user.txt
/^$/{
N
/^\n$/D
}
多行删除命令完成工作的原因是,当遇到两个空行时,D命令只删除两个空行中的第一个。下一次遍历该脚本时,
这个空行将导致另一行被读入模式空间。
如果那行不为空,那么两行都输出,因此确保了输出一个空行。换句话说,当模式空间中有两个空行时,只有第一
个空行被删除。当一个空行后面跟有文本时,模式空间可以正常输出。
P命令输出多行模式空间的第一部分,直到第一个嵌入的换行符为止。在执行完脚本的最后一个命令之后,模式空
间的内容自动输出。
P命令经常出现在N命令之后和D命令之前。
这三个命令能建立一个输入、输出循环,用来维护两行模式空间,但是一次只输出一行。
这个循环的目的是只输出模式空间的第一行,然后返回到脚本的顶端将所有的命令应用于模式空间的第二行。
没有这个循环,当执行脚本中的最后一个命令时,模式空间中的这两行都将被输出。
删除文件倒数第二行
sed 'N;$!P;D' a.txt
删除文件最后两行
sed 'N;$!P;$!D;$d' a.txt
模式空间是容纳当前输入行的缓冲区。还有一个成为保持空间(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
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'
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的方式能让我们的处理命令更快捷,提高工作效率
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
读前处理 行处理 读后处理
awk 'BEGIN {print "hello,World"}'
awk 'BEGIN{print "start handle file"}{print}END{print"stop handle file"}' /etc/passwd
练习
先输出 开始处理文件
取当前系统所有用户的名字 uid 和 shell
最后输出 处理完毕
定址方法: 正则,变量,比较和关系运算
正则需要用//包围起来
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] 数字
\< 单词头单词一般以空格或特殊字符做分隔,连续的字符串被当做单词
\> 单词尾
\ 转义字符
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
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
++ 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
!~
关系比较字符串时要把字符串用双引号引起来
< <= > >= != ==
$ 字段引用需要加$,而变量引用直接用变量名取
运算符+ - * / % ++ –
\ \自身
\$ 转义$
\t 制表符
\b 退格符
\r 回车符
\n 换行符
\c 取消换行
a=root
awk –v var=$a –F“:” ’$1==var{print $0}’ /etc/passwd
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"]}'
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"}'
若有多个动作,则要用大括号将动作体包含起来if (条件) {动作1;动作2}
# awk -F : '{if ($1 == "root") print $1}' /etc/passwd
# awk -F: '{if ($1 == "root") {print $1;print $6} }' /etc/passwd
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
上面两个命令是等价的,要么用分号隔开,表示第一个动作体的结束,要么将动作体用大括号定位范围
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
# 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
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
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
# 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
# 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
[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
[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
rand函数(内置函数 srand 使用参数awk 'BEGIN{x=rand();print x}'作为随机数种子。当参数缺省的时候,使用当
前时间作为随机数种子。)
[root@manager ~]# awk 'BEGIN{x=rand();print x}'
0.237788
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
[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!
[root@manager ~]# awk 'BEGIN{info="this is test2010test!";print index(info,"test")?"ok":"not found";}'
ok
[root@manager ~]# awk 'BEGIN{info="hello";print length(info)}'
5
[root@manager ~]# awk 'BEGIN{info="hello world";print substr(info,4,10)}'
lo world
[root@manager ~]# awk 'BEGIN{info="hello 2016world";print match(info,/[0-9]+/)?"ok":"none";}'
ok
[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
函数 | 说明 |
---|---|
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 特殊变量。 |
[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
[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}}'
[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
点击这里 | 点击这里 |
---|---|
函数名 | 说明 |
mktime( YYYY MM DD HH MM SS[ DST]) | 生成时间格式 |
strftime([format [, timestamp]]) | 格式化时间输出,将时间戳转为时间字符串 具体格式,见下表. |
systime() | 得到时间戳,返回从1970年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
格式 | 描述 |
---|---|
%a | 星期几的缩写(Sun) |
%A | 星期几的完整写法(Sunday) |
%b | 月名的缩写(Oct) |
%B | 月名的完整写法(October) |
%c | 本地日期和时间 |
%d | 十进制日期 |
%D | 日期 08/20/99 |
%e | 日期,如果只有一位会补上一个空格 |
%H | 用十进制表示24小时格式的小时 |
%I | 用十进制表示12小时格式的小时 |
%j | 从1月1日起一年中的第几天 |
%m | 十进制表示的月份 |
%M | 十进制表示的分钟 |
%p | 12小时表示法(AM/PM) |
%S | 十进制表示的秒 |
%U | 十进制表示的一年中的第几个星期(星期天作为一个星期的开始) |
%w | 十进制表示的星期几(星期天是0) |
%W | 十进制表示的一年中的第几个星期(星期一作为一个星期的开始) |
%x | 重新设置本地日期(08/20/99) |
%X | 重新设置本地时间(12:00:00) |
%y | 两位数字表示的年(99) |
%Y | 当前月份 |
%Z | 时区(PDT) |
%% | 百分号(%) |
是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。在编写程序时经常会用到此函数。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
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/bash
awk '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