知识集锦2
通配符
通配符是shell在做PathnameExpansion时用到的。说白了一般只用于文件名匹配,它是由shell解析的,比如 find,ls,cp,mv等 shell常见通配符
1 | *:匹配0或多个字符 |
- shell 元字符
1 | IFS:<tab>/<space>/<enter> |
- shell转义符
1 | '':硬转义,内部所有shell元字符,通配符都会被关掉 |
find文件查找
- 实时查找工具,通过遍历指定路径下的文件系统完成文件查找
- 工作特点
- 查找速度略慢
- 精确查找
- 实时查找
- 可以满足多种条件匹配
1 | find [选项] [路径] [查找条件 + 处理动作] |
查找条件
- 查找条件
1 | 根据文件名查找: |
- 根据文件名查找
1 | [root@localhost ~]# find /etc -name "ifcfg-ens33" |
- 按文件大小
1 | [root@localhost ~]# find /etc -size +5M # 大于5M |
- 指定查找的目录深度
1 | [root@localhost ~]# find / -maxdepth 3 -a -name "ifcfg-ens33" # 最大查找深度 |
- 按时间找
1 | [root@localhost ~]# find /etc -mtime +5 # 修改时间超过5天 |
- 按照文件属主、属组找
1 | [root@localhost ~]# find /home -user xwz # 属主是xwz的文件 |
- 按文件类型
1 | [root@localhost ~]# find /dev -type d |
- 按文件权限
1 | [root@localhost ~]# find / -perm 644 -ls |
- 按正则表达式
1 | [root@localhost ~]# find /etc -regex '.*ifcfg-ens[0-9][0-9]' |
- 条件组合
1 | -a:多个条件and并列 |
处理动作
1 | ‐print:默认的处理动作,显示至屏幕 |
正则表达式
正则表达式是用来匹配字符串的,针对文件内容的文本过滤工具里,大都用到正则表达式,如vi,grep,awk, sed等
1 | ##字符匹配 |
- 扩展正则表达式
1 | ##字符匹配 |
Linux三剑客之grep
grep作用:过滤文本内容
选项 | 描述 |
---|---|
-E :–extended–regexp | 模式是扩展正则表达式(ERE) |
-i :–ignore–case | 忽略大小写 |
-n: –line–number | 打印行号 |
-o:–only–matching | 只打印匹配的内容 |
-c:–count | 只打印每个文件匹配的行数 |
-B:–before–context=NUM | 打印匹配的前几行 |
-A:–after–context=NUM | 打印匹配的后几行 |
-C:–context=NUM | 打印匹配的前后几行 |
–color[=WHEN] | 匹配的字体颜色,别名已定义了 |
-v:–invert–match | 打印不匹配的行 |
-e | 多点操作eg:grep -e “^s” -e “s$” |
样本文件内容
1 | [root@localhost ~]# cat m |
实例
实例1:打印出所有的a无论大小写 : -i选项
1 | [root@localhost ~]# grep -i "a" test |
实例2:打印出所有的a无论大小写,并且显示该字符串所在的行 : -n选项
1 | [root@localhost ~]# grep -in "a" test |
实例3:仅仅打印出所有匹配的字符串: -o选项
1 | [root@localhost ~]# grep -io "a" test |
实例4:打印出匹配的字符串有多少行 -c选项
1 | [root@localhost ~]# grep -ic "a" test |
实例5:打印出字符S前面的2行 -B
1 | [root@localhost ~]# grep -B 2 "S" test |
实例6:打印出字符S后面的2行 -A
1 | [root@localhost ~]# grep -A 2 "S" test |
实例7:打印出字符S前后2行 -C
1 | [root@localhost ~]# grep -C 2 "S" test |
实例8:打印出不包含大小s的所有行 取反 -v
1 | [root@localhost ~]# grep -iv "S" test |
grep可以从文件当中直接搜索某个关键词,也可以从标准输入里面搜索
1 | [root@localhost ~]# grep root /etc/passwd |
正则表达式(基于grep)
- 功能就是用来检索、替换那些符合某个模式(规则)的文本,正则表达式在每种语言中都会有;
- 正则表达式就是为了处理大量的文本或字符串而定义的一套规则和方法
- 通过定义的这些特殊符号的辅助,系统管理员就可以快速过滤,替换或输出需要的字符串
- Linux正则表达式一般以行为单位处理
基础正则表达式
符号 | 描述 |
---|---|
. | 匹配任意单个字符(必须存在) |
^ | 匹配以某个字符开头的行 |
$ | 配以什么字符结尾的行 |
* | 匹配前面的一个字符出现0次或者多次;eg:a*b |
.* | 表示任意长度的任意字符 |
[] | 表示匹配括号内的一个字符 |
[^] | 匹配[^字符]之外的任意一个字符 |
[] | 匹配非[^字符]内字符开头的行 |
< | 锚定 单词首部;eg:<root |
> | 锚定 单词尾部:eg:root> |
{m,n} | 表示匹配前面的字符出现至少m次,至多n次 |
() | 表示对某个单词进行分组;\1表示第一个分组进行调用 |
扩展正则
- egrep …
- grep -E …
- 扩展正则支持所有基础正则;并有补充
- 扩展正则中{}和[]不用转义可以直接使用;
符号 | 描述 | |
---|---|---|
+ | 表示前面的字符至少出现1次的情况 | |
\ | 表示“或” | |
? | 表示前面的字符至多出现1次的情况 |
最常用
查看配置文件时去除所有的注释和空行
1 | [root@localhost ~]# grep -Ev "^#|^$" /etc/ssh/sshd_config |
这里解释下:
grep -Ev "^#|^$" /etc/ssh/sshd_config
是一个Linux命令,用于从/etc/ssh/sshd_config
文件中筛选出非注释行和非空行。这里使用了grep
命令,结合正则表达式和选项来实现这一目标。
grep
: 是一个强大的文本搜索工具,用于搜索文件中的特定模式。-E
: 告诉grep
使用扩展正则表达式(Extended Regular Expression)。这允许使用更高级的正则表达式语法。-v
: 表示反向选择,即选择不匹配指定模式的行。"^#|^$"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
: 是一个扩展正则表达式,它匹配两种类型的行:
- `^#`: 以`#`字符开头的行,这通常是注释行。
- `^$`: 空行,即只包含行首和行尾的行。
- `/etc/ssh/sshd_config`: 是要搜索的文件路径,该文件通常包含SSH服务器的配置选项。
因此,`grep -Ev "^#|^$" /etc/ssh/sshd_config`这个命令的作用是从`/etc/ssh/sshd_config`文件中筛选出所有非注释行和非空行,并将这些行输出到终端。这样,你可以更容易地查看和编辑SSH服务器的实际配置选项,而不必被注释和空行所干扰。
~~~
sed '/^\s*#/d; /^\s*$/d' filename | grep -v '^$'
~~~
`sed '/^\s*#/d; /^\s*$/d' filename | grep -v '^$'` 是一个在Linux shell中使用的命令组合,用于处理文本文件并输出特定的内容。这个命令组合的目的是从文件中去除所有的注释行和空行。下面我逐一解释每个部分的作用:
`sed` 是一个流编辑器,用于对输入流(或文件)进行基本的文本转换。在这个命令中,`sed` 接收两个正则表达式作为编辑命令,并应用于文件 `filename`。
1. `/^\s*#/d`:这个命令告诉 `sed` 删除所有以零个或多个空白字符(`\s*`)开头,后面紧跟一个 `#` 符号的行。这通常用于删除以 `#` 开头的注释行。
2. `/^\s*$/d`:这个命令告诉 `sed` 删除所有只包含零个或多个空白字符的行。这用于删除空行。
`grep` 是一个强大的文本搜索工具,用于搜索特定的模式。在这里,`-v` 选项表示“反向选择”,即选择不匹配指定模式的行。
`'^$'` 是一个正则表达式,匹配只包含行首和行尾的行,即空行。因此,`grep -v '^$'` 会从输入中排除所有空行。
将 `sed` 和 `grep` 命令通过管道 `|` 连接起来,可以首先使用 `sed` 删除注释和空行,然后使用 `grep` 进一步删除可能由 `sed` 留下的任何额外的空行。这通常用于确保输出中没有空行。
综合来说,`sed '/^\s*#/d; /^\s*$/d' filename | grep -v '^$'` 这个命令组合会从 `filename` 文件中删除所有的注释行和空行,并将结果输出到终端。
# Linux三剑客之sed
Linux sed命令是利用script来处理文本文件。
sed可依照script的指令,来处理、编辑文本文件。
sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
## 语法
```bash
sed的命令格式: sed [option] 'sed command' filename
sed的脚本格式:sed [option] ‐f 'sed script' filename
常用选项:
‐n :只打印模式匹配的行
‐e :直接在命令行模式上进行sed动作编辑,此为默认选项
‐f :将sed的动作写在一个文件内,用–f filename 执行filename内的sed动作
‐r :支持扩展表达式
‐i :直接修改文件内容
查询文本的方式
使用行号和行号范围
x:行号
x,y:从x行到y行
x,y!:x行到y行之外
/pattern:查询包含模式的行
/pattern/, /pattern/:查询包含两个模式的行
/pattern/,x:x行内查询包含模式的行
x,/pattern/:x行后查询匹配模式的行
动作说明
1 | 常用选项: |
a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)
c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d :删除,因为是删除啊,所以 d 后面通常不接任何东西;
i :插入, i的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行
s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!
实例
在testfile文件的第四行后添加一行,并将结果输出到标准输出
1 | [root@localhost ~]# sed -e 4a\newline test |
以行为单位的新增/删除(nl是个整体,不可分割)
将 /etc/passwd 的内容列出并且列印行号,同时,请将第 2~5 行删除
1 | [root@localhost ~]# nl /etc/passwd | sed '2,5d' |
sed 的动作为 ‘2,5d’ ,那个 d 就是删除!因为 2-5 行给他删除了,所以显示的数据就没有 2-5 行罗~ 另外,注意一下,原本应该是要下达 sed -e 才对,没有 -e 也行啦!同时也要注意的是, sed 后面接的动作,请务必以 ‘’ 两个单引号括住喔!
只要删除第 2 行
1 | [root@localhost ~]# nl /etc/passwd | sed '2d' |
要删除第 3 到最后一行
1 | [root@localhost ~]# nl /etc/passwd | sed '3,$d' |
在第二行后(亦即是加在第三行)加上『hello world』字样
1 | [root@localhost ~]# nl /etc/passwd | sed '2a\hello world' |
加在第二行前面
1 | [root@localhost ~]# nl /etc/passwd | sed '2i\hello world' |
增加多行文字
1 | [root@localhost ~]# nl /etc/passwd | sed '2a\hello world\ |
以行为单位的替换与显示
将第2-5行的内容取代成为『No 2-5 number』
1 | [root@localhost ~]# nl /etc/passwd | sed '2,5c\No 2-5 number' |
仅列出 /etc/passwd 文件内的第 5-7 行
1 | [root@localhost ~]# nl /etc/passwd | sed -n '5,7p' |
数据的搜寻并显示
搜索 /etc/passwd有root关键字的行
1 | [root@localhost ~]# nl /etc/passwd | sed -n '/root/p' |
数据的搜寻并删除
删除/etc/passwd所有包含root的行,其他行输出
1 | [root@localhost ~]# nl /etc/passwd | sed '/root/d' |
数据的搜寻并执行命令
搜索/etc/passwd,找到root对应的行,执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把bash替换为blueshell,再输出这行
1 | [root@localhost ~]# nl /etc/passwd | sed -n '/root/{s/bash/blueshell/p;q}' |
最后的q是退出,不然会继续找下去
数据的搜寻并替换
除了整行的处理模式之外, sed 还可以用行为单位进行部分数据的搜寻并取代
1 | sed 's/要被取代的字串/新的字串/g' |
查询 IP
原始信息
1 | yum -y install net-tools |
取有IP地址那一行
1 | [root@localhost ~]# ifconfig | sed -n '/netmask/p' |
注:-n
选项告诉 sed
不要输出任何内容,除非明确指定要输出。
/netmask/p
是一个 sed
命令,它告诉 sed
查找包含“netmask”的行,并打印(p
)这些行。
删除IP地址前面和后面的东西
1 | [root@localhost ~]# ifconfig | sed -n '/netmask/p' | sed 's/^.*inet //g' | sed 's/ netmask.*$//g' |
注:
ifconfig
:
ifconfig
命令用于显示或配置网络接口的参数。当你运行 ifconfig
,它会列出所有网络接口及其相关的配置信息,如IP地址、子网掩码等。
sed -n '/netmask/p'
:
这个 sed
命令用于从 ifconfig
的输出中筛选出包含 “netmask” 的行。-n
选项告诉 sed
默认不输出任何内容,而 /netmask/p
则指定只打印包含 “netmask” 的行。
sed 's/^.\*inet //g'
:
这个 sed
命令用于处理上一步输出的行。s/^.*inet //g
是一个替换命令,它的作用是将每行中从开头到 “inet “ 的部分替换为空(即删除)。这通常用于从 ifconfig
的输出中提取IP地址,因为IP地址通常紧跟在 “inet “ 后面。
sed 's/ netmask.\*$//g'
:
这个 sed
命令进一步处理上一步的输出。s/ netmask.*$//g
也是一个替换命令,它的作用是将每行中从 “ netmask” 开始到行尾的部分替换为空(即删除)。这用于删除IP地址后面的子网掩码和其他相关信息,只保留IP地址本身。
综合以上步骤,整个命令组合的作用是从 ifconfig
的输出中提取每个网络接口的IP地址。不过,需要注意的是,现代Linux发行版可能推荐使用 ip
命令来替代 ifconfig
,因为 ifconfig
在某些系统中可能已经被标记为过时或不再维护。如果你使用的是较新的Linux系统,建议考虑使用 ip
命令来提取IP地址。
取第一行
1 | [root@localhost ~]# ifconfig | sed -n '/netmask/p' | sed 's/^.*inet //g' | sed 's/ netmask.*$//g' | sed -n '1p' |
-n
:这个选项告诉sed
不要输出任何内容,除非明确指定。通常与p
命令一起使用,以仅输出匹配的行。'1p'
:这是一个sed
脚本,它告诉sed
打印(p
)第一行(1
)。
可以在末尾加g替换每一个匹配的关键字,否则只替换每行的第一个
另一种方式:
1 | [root@localhost ~]# ip a|sed -n '/inet /p'|sed 's/^.*inet //g'|sed 's/\/.*$//g'|sed -n '2p' |
这个命令组合使用 ip
, sed
等命令来提取特定网络接口(通常是第二个网络接口)的IP地址。这里是对命令的逐步解释:
ip a
:
这个命令是 ip address
的简写,用于显示所有网络接口的地址信息。输出通常会包括接口的名称、IP地址、子网掩码、广播地址等。
sed -n '/inet /p'
:
这个 sed
命令用于从 ip a
的输出中筛选出包含 “inet “ 的行。-n
选项告诉 sed
默认不输出任何内容,而 /inet /p
则指定只打印包含 “inet “ 的行。这通常用于提取IPv4地址。
sed 's/^.\*inet //g'
:
这个 sed
命令用于处理上一步输出的行。s/^.*inet //g
是一个替换命令,它的作用是将每行中从开头到 “inet “ 的部分替换为空(即删除)。这用于从 ip a
的输出中提取出 “inet “ 后面的部分,通常是IP地址。
sed 's/\/.\*$//g'
:
这个 sed
命令进一步处理上一步的输出。s/\/.*$//g
是一个替换命令,它的作用是将每行中从 “/“(子网掩码的开始)到行尾的部分替换为空(即删除)。这用于从IP地址和子网掩码的组合中只保留IP地址。
sed -n '2p'
:
这个 sed
命令用于输出处理后的第二行。这通常用于提取第二个网络接口的IP地址,因为 ip a
的输出中,第一个网络接口(通常是 lo
,即回环接口)通常位于列表的顶部。
综合以上步骤,整个命令组合的作用是提取系统中第二个网络接口的IPv4地址。
需要注意的是,这个命令组合假设 ip a
的输出中第二个包含 “inet “ 的行对应于第二个网络接口的IP地址。在大多数情况下,这是正确的,但如果系统配置不同,可能需要调整命令以适应特定情况。
多点编辑
一条sed命令,删除/etc/passwd第三行到末尾的数据,并把bash替换为blueshell
1 | [root@localhost ~]# nl /etc/passwd | sed -e '3,$d' -e 's/bash/blueshell/' |
-e表示多点编辑,第一个编辑命令删除/etc/passwd第三行到末尾的数据,第二条命令搜索bash替换为blueshell。
注:这个命令组合做了几件事情。让我们逐步分析它:
- nl /etc/passwd
nl
命令用于给文件的每一行加上行号。在这里,它会给 /etc/passwd
文件的每一行加上行号。/etc/passwd
文件通常包含系统用户的账户信息。
- sed -e ‘3,$d’ -e ‘s/bash/blueshell/‘
sed
是一个流编辑器,用于对输入流(或文件)进行基本的文本转换。
-e
选项允许你指定一个或多个 sed
编辑命令。
'3,$d'
: 这个命令告诉sed
删除从第3行到最后一行的所有内容。3,$
是一个地址范围,其中3
是起始行号,$
表示最后一行。d
是一个命令,表示删除匹配的行。's/bash/blueshell/'
: 这是一个替换命令,它告诉sed
将每一行中的第一个 “bash” 替换为 “blueshell”。
需要注意的是,这两个 sed
命令是顺序执行的。首先,所有从第3行到最后一行的内容都会被删除。然后,在剩下的内容中,所有的 “bash” 都会被替换为 “blueshell”。
因此,整个命令组合 nl /etc/passwd | sed -e '3,$d' -e 's/bash/blueshell/'
的作用是:
- 给
/etc/passwd
文件的每一行加上行号。 - 删除从第3行到最后一行的所有内容。
- 在剩下的内容中,将所有的 “bash” 替换为 “blueshell”。
最终,你会看到 /etc/passwd
文件的前两行(带有行号),并且如果这两行中有 “bash” 的话,它会被替换为 “blueshell”。
直接修改文件内容(危险动作)
1 | [root@localhost ~]# cat test |
加i参数就是直接修改
1 | [root@localhost ~]# sed -i 's/ \.$ / \! /g' test |
注:这个 sed
命令做了以下事情:
-i
: 这个选项告诉sed
直接修改输入文件,而不是将结果输出到标准输出(通常是终端)。's/ \.$ / \! /g'
: 这是一个sed
替换命令,其格式是s/pattern/replacement/flags
。\.
: 匹配一个实际的点字符(.
)。因为在正则表达式中,.
是一个特殊字符,表示匹配任何字符(除了换行符)。所以,为了匹配实际的点字符,我们需要使用反斜杠\
来转义它。$
: 匹配行的结尾。\.$
: 因此,\.$
匹配以点字符结尾的行。\!
: 这是替换字符串,表示将匹配到的点字符替换为感叹号!
。g
: 这是一个全局标志,表示替换每一行中所有匹配到的模式,而不仅仅是每一行的第一个匹配。
综上所述,这个 sed
命令会在文件 test
中查找所有以点字符结尾的行,并将这些点字符替换为感叹号。
例如,如果 test
文件的内容如下:
1 | This is a line. |
运行这个 sed
命令后,test
文件的内容将变为:
1 | This is a line! |
注意:使用 -i
选项时要小心,因为它会直接修改文件。如果你不确定结果是否正确,可以先不使用 -i
选项来查看结果,然后再决定是否直接修改文件。
\利用 sed 直接在最后一行加入 # test
1 | [root@localhost ~]# sed -i '$a\# test' test |
注:
-i
: 如之前所述,这个选项告诉sed
直接修改输入文件,而不是将结果输出到标准输出。'$a\# test'
: 这是一个sed
命令,用于在文件的最后一行之后追加文本。$
: 这是一个地址,表示文件的最后一行。a
: 这是一个命令,表示在指定的地址之后追加文本。# test
: 这是要追加的文本内容。
Linux三剑客之awk
使用方法
1 | awk '{pattern + action}' {filenames} |
其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。
awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。
通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。
awk 的原理
1 | [root@localhost ~]# awk -F: '{print $0}' /etc/passwd |
执行 awk 时,它依次对/etc/passwd 中的每一行执行 print 命令。
1 | [root@localhost ~]# awk -F":" '{print $1}' /etc/passwd |
-F参数:指定分隔符,可指定一个或多个
print 后面做字符串的拼接
变量名 | 属性 |
---|---|
$0 | 当前记录 |
$1~$n | 当前记录的第n个字段 |
FS | 输入字段分割符 默认是空格 |
RS | 输入记录分割符 默认为换行符 |
NF | 当前记录中的字段个数,就是有多少列 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFS | 输出字段分割符 默认也是空格 |
ORS | 输出的记录分割符 默认为换行符 |
注:内置变量很多,参阅相关资料
实例一:只查看test.txt文件(100行)内第20到第30行的内容(企业面试)
1 | [root@localhost ~]# seq 100 > test.txt |
实例二:已知test.txt文件内容为
1 | [root@localhost ~]# cat test.txt |
请从该文件中过滤出’aaron’字符串与1234567,最后输出的结果为:aaron 1234567
1 | [root@localhost ~]# awk -F '[ ,]+' '{print $3" "$NF}' test.txt #用[]可以放多个分隔符 |
BEGIN 和 END 模块
BEGIN只执行一次并且执行在主体代码块之前。
END只执行一次并且执行在主体代码块之后。
BEGIN可以抛开文件单独执行,结果类似于echo而END不可以。
BEGIN中没有文件的读取变量而END是有的。但END中的$0是awk处理到最后的文本样式。
实例一:统计/etc/passwd的账户人数
1 | awk 'BEGIN {count=0;print "[start] user count is "count}{count++;print $0} END{print "[end] user count is "count}' /etc/passwd |
count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开。这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0
1 | [root@localhost ~]# awk '{count++;print $0;} END{print "user count is "count}' /etc/passwd |
实例二:统计某个文件夹下的文件占用的字节数
1 | [root@localhost ~]# ll | awk 'BEGIN {size=0} {size=size+$5} END{print "size is ",size}' |
awk运算符
运算符 | 描述 | ||
---|---|---|---|
赋值运算符 | |||
= += -= *= /= %= ^= **= | 赋值语句 | ||
逻辑运算符 | |||
\ | \ | 逻辑或 | |
&& | 逻辑与 | ||
正则运算符 | |||
~ !~ | 匹配正则表达式和不匹配正则表达式 | ||
关系运算符 | |||
< <= > >= != == | 关系运算符 | ||
算数运算符 | |||
+ - | 加,减 | ||
* / & | 乘,除与求余 | ||
+ - ! | 一元加,减和逻辑非 | ||
^ *** | 求幂 | ||
++ – | 增加或减少,作为前缀或后缀 | ||
其他运算符 | |||
$ | 字段引用 | ||
空格 | 字符串链接符 | ||
?: | 三目运算符 | ||
in | 数组中是否存在某键值 |
awk 赋值运算符:a+=5;等价于: a=a+5;其他同类
1 | [root@node-1 ~]# awk 'BEGIN{a=5;a+=5;print a}' |
awk逻辑运算符:判断表达式 a>2&&b>1为真还是为假,后面的表达式同理
1 | [root@node-1 ~]# awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}' |
awk正则运算符:
1 | [root@node-1 ~]# awk 'BEGIN{a="100testaa";if(a~/100/) {print "OK"}else {print "NO"}}' |
关系运算符:
如: > < 可以作为字符串比较,也可以用作数值比较,关键看操作数如果是字符串就会转换为字符串比较。两个都为数字才转为数值比较。字符串比较:按照ascii码顺序比较。
1 | [root@node-1 ~]# awk 'BEGIN{a="11";if(a>=9){print"OK"}}' |
awk 算术运算符:
说明,所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0。
1 | [root@node-1 ~]# awk 'BEGIN{a="b";print a++,++a}' |
这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值
三目运算符 ?:
1 | [root@node-1 ~]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}' |
常用 awk 内置变量
变量名 | 属性 |
---|---|
$0 | 当前记录 |
$1~$n | 当前记录的第n个字段 |
FS | 输入字段分割符 默认是空格 |
RS | 输入记录分割符 默认为换行符 |
NF | 当前记录中的字段个数,就是有多少列 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFS | 输出字段分割符 默认也是空格 |
ORS | 输出的记录分割符 默认为换行符 |
注:内置变量很多,参阅相关资料
字段分隔符 FS
FS=”\t” 一个或多个 Tab 分隔
1 | [root@node-1 ~]# cat tab.txt |
FS=”[[:space:]+]” 一个或多个空白空格,默认的,匹配到不符合的就停止
1 | [root@node-1 ~]# awk -F [[:space:]+] '{print $1,$2,$3,$4,$5}' tab.txt |
FS=”[“ “]+” 以一个或多个空格或:分隔
1 | [root@node-1 ~]# awk -F [" "]+ '{print $1,$2,$3}' hello.txt |
字段数量 NF :显示满足用:分割,并且有8个字段的
1 | [root@node-1 ~]# awk -F ":" 'NF==8{print $0}' hello.txt |
记录数量 NR
1 | [root@node-1 ~]# ifconfig ens33 | awk -F [" "]+ 'NR==2{print $3}' |
RS 记录分隔符变量
将 FS 设置成”\n”告诉 awk, 每个字段都占据一行。通过将 RS 设置成””,还会告诉 awk每个地址记录都由空白行分隔。
1 | [root@node-1 ~]# cat awk.txt |
在””分割符之内,符合\n分割的会被打印出来
OFS 输出字段分隔符
1 | [root@node-1 ~]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2,$3}' hello.txt |
ORS 输出记录分隔符
1 | [root@node-1 ~]# cat awk.txt |
awk正则
元字符 | 功能 | 示例 | 解释 | ||
---|---|---|---|---|---|
^ | 首航定位符 | /^root/ | 匹配所有以root开头的行 | ||
$ 行尾定位符 \ | /root$/ | 匹配所有以root结尾的行 | |||
. | 匹配任意单个字符 | /r..t/ | 匹配字母r,然后两个任意字符,再以t结尾的行 | ||
* | 匹配0个或多个前导字符(包括回车) | /a*ool/ | 匹配0个或多个a之后紧跟着ool的行,比如ool,aaaaool等 | ||
+ | 匹配1个或多个前导字符 | /a+b/ | ab, aaab | ||
? | 匹配0个或1个前导字符 | /a?b/ | b,ab | ||
[] | 匹配指定字符组内的任意一个字符 | /^[abc]/ | 匹配以a或b或c开头的行 | ||
[^] | 匹配不在指定字符组内任意一个字符 | /^[^abc]/ | 匹配不以字母a或b或c开头的行 | ||
() | 子表达式组合 | /(rool)+/ | 表示一个或多个rool组合,当有一些字符需要组合时,使用括号括起来 | ||
\ | 或者的意思 | /(root)\ | B/ | 匹配root或者B的行 | |
\ | 转义字符 | /a/// | 匹配a// | ||
匹配,不匹配的条件语句 | $1~/root/ | 匹配第一个字段包含字符root的所有记录 | |||
x{m}x{m,}x{m,n} | x重复m次x重复至少m次x重复至少m次,但是不超过n次 | /(root){3}//(root){3,}//(root){3,6}/ |
正则应用
规则表达式
awk '/REG/{action} ' file
,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理
1 | [root@node-1 ~]# awk '/root/{print$0}' /etc/passwd |
布尔表达式
awk '布尔表达式{action}' file
仅当对前面的布尔表达式求值为真时, awk 才执行代码块。
1 | [root@node-1 ~]# awk -F: '$1=="root"{print$0}' /etc/passwd |
awk 的 if、循环和数组
if
条件语句
awk 提供了非常好的类似于 C 语言的 if 语句。
1 | { |
使用 if 语句还可以将代码:
1 | ! /matchme/ { print $1 $3 $4 } |
转换成:
1 | { |
while
循环结构
我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。 awk 还有”do…while”循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。
它类似于其它语言中的”repeat…until”循环。以下是一个示例:
do…while 示例
1 | { |
与一般的 while 循环不同,由于在代码块之后对条件求值, “do…while”循环永远都至少执行一次。换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。
for 循环
awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:
1 | for ( initial assignment; comparison; increment ) { |
以下是一个简短示例:
1 | for ( x=1;x<=4;x++ ) { |
break 和 continue
此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。使用这些语句可以更好地控制 awk 的循环结构。
1 |
|
continue 语句补充了 break
1 | x=1 |
continue在for中使用
1 |
|
数组
AWK 中的数组都是关联数组,数字索引也会转变为字符串索引
在awk中,数组叫关联数组,与我们在其它编程语言中的数组有很大的区别。关联数组,简单来说,类似于python语言中的dict、java语言中的map,其下标不再局限于数值型,而可以是字符串,即下标为key,value=array[key]。竟然为key,那其下标也不再是有序的啦。
1 |
|
用 awk 中查看服务器连接状态并汇总
1 | [root@node-1 ~]# netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' |
常用字符串函数
字符串函数的应用
在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info
1 | [root@node-1 ~]# awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}' |
- BEGIN { … }:
BEGIN
是一个特殊的awk
模式,它在处理任何输入行之前执行。在这个BEGIN
块中,你可以初始化变量或执行其他只需要执行一次的操作。 - info=”this is a test2010test!”: 这行代码在
BEGIN
块中初始化了一个名为info
的变量,并给它赋了一个字符串值"this is a test2010test!"
。 - gsub(/[0-9]+/,”!”,info):
gsub
是awk
中的一个函数,用于在字符串中进行全局替换。这里,它查找info
变量中所有的一个或多个连续数字(由正则表达式[0-9]+
定义),并将它们替换为感叹号!
。
所以,这行代码将 info
中的所有数字替换为感叹号。
- print info: 这行代码打印出修改后的
info
变量的值。
如果查找到数字则匹配成功返回 ok,否则失败,返回未找到
1 | [root@node-1 ~]# awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}' |
- BEGIN { … }: 正如之前提到的,
BEGIN
是一个特殊的awk
模式,它在处理任何输入行之前执行。 - info=”this is a test2010test!”: 这行代码在
BEGIN
块中初始化了一个名为info
的变量,并给它赋了一个字符串值"this is a test2010test!"
。 - index(info,”test”):
index
是awk
的一个内置函数,它返回子字符串在字符串中首次出现的位置(基于1的索引)。如果子字符串没有在字符串中找到,则返回0。在这个例子中,index(info,"test")
会返回8
,因为 “test” 首次出现在info
变量的第8个字符位置。 - index(info,”test”)?”ok”:”no found”: 这是一个三元操作符,它基于
index
函数的返回值来决定输出什么。如果index
返回非零值(即找到了子字符串),则输出 “ok”;否则输出 “no found”。 - print …: 这行代码打印出三元操作符的结果。
从第 4 个 字符开始,截取 10 个长度字符串
1 | [root@node-1 ~]# awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' |
BEGIN { … }: 正如之前提到的,
BEGIN
是一个特殊的awk
模式,它在处理任何输入行之前执行。info=”this is a test2010test!”: 这行代码在
BEGIN
块中初始化了一个名为info
的变量,并给它赋了一个字符串值"this is a test2010test!"
。substr(info,4,10):
substr
是awk
的一个内置函数,用于从字符串中提取子字符串。它接受三个参数:源字符串、起始位置和要提取的字符数。在这个例子中,它从info
变量的第4个字符开始(基于1的索引),提取长度为10的子字符串。对于
info="this is a test2010test!"
,从第4个字符开始(即 ‘i’),提取10个字符得到的子字符串是 “s is a tes”。print substr(info,4,10): 这行代码打印出使用
substr
函数提取的子字符串。
分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。 并不是从数组下标1…n 开始
1 | [root@node-1 ~]# awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' |
- BEGIN { … }: 如前所述,
BEGIN
块在awk
开始处理任何输入行之前执行。 - info=”this is a test”: 在
BEGIN
块中初始化一个名为info
的变量,并给它赋了一个字符串值"this is a test"
。 - split(info,tA,” “):
split
函数用于将字符串info
根据指定的分隔符(在这个例子中是空格" "
)分割成一个数组tA
。这样,tA[1]
将会是"this"
,tA[2]
将会是"is"
,以此类推。 - print length(tA): 打印数组
tA
的长度。由于字符串"this is a test"
被空格分割成了四个部分,所以输出将是4
。 - for(k in tA) { print k, tA[k] }: 这是一个
for
循环,用于遍历数组tA
。在awk
中,当你遍历数组时,k
会自动被赋值为数组的索引(在这个例子中是数字),而tA[k]
则是相应的值。这个循环会打印出数组的每一个索引和对应的值。 - 首先,它打印出数组的长度
4
。然后,它遍历数组并打印出每个元素的索引和值。注意,在awk
中,数组的索引默认是从1
开始的,而不是从0