[TOC]
正则表达式与文本搜寻
元字符
.
匹配任意单个字符(单行模式下不匹配换行符)*
匹配前一个字符任意次[]
匹配范畴内任意一个字符^
匹配结尾$
匹配结尾\
本义前面的特殊字符
扩大元字符
+
先前的项能够匹配一次或屡次。?
先前的项是可选的,最多匹配一次。|
匹配后面或前面的正则表达式, "或"()
分组
反复
一个正则表达式前面能够追随多种反复操作符之一。{n} 先前的项将匹配恰好 n 次。{n,} 先前的项能够匹配 n 或更屡次。{n,m} 先前的项将匹配至多 n 词,然而不会超过 m 次
find 命令
递归地在目录中查找文件find [门路...] 表达式表达式 查找范畴 -maxdepth <level> # 目录递归最大层数 -mindepth <level> # ? 按文件名查找 -name "模式" # 残缺匹配根本的文件名, 应用"通配符"匹配根本的文件名 -regex "模式" # 残缺匹配整个门路(并非单单匹配文件名), 应用"正则"匹配根本的文件名 -iregex "模式" # 残缺匹配整个门路(并非单单匹配文件名) , 应用"正则"匹配根本的文件名, 但不辨别大小写 -regextype <reg_type> # 扭转正则表达式语法, 可选: emacs (this is the default), posix-awk, posix-basic, posix-egrep and posix-extended 按文件类型查找 -type 类型 # b 块设施, c 字符设施, d 目录, p 命名管道, f 一般文件, l 符号链接, s 套接字 按工夫查找 # 数字参数 # +n 在这之前的 # -n 在这之后的 # n 正好处于该时刻 -daystart # 从当日0点为基准, 而不是以后时刻, 影响下述几种工夫类型. -atime <n> # Access, 最初拜访工夫, 单位为天(但理论是以以后工夫为基准) -ctime <n> # Change, 文件i节点批改工夫, 单位为天 -mtime <n> # Modify, 文件内容批改工夫, 单位为天 -amin <n> # 相似 atime, 但单位是分钟 -ctim <n> # 相似 ctime, 但单位是分钟 -mmin <n> # 相似 mtime, 但单位是分钟 按大小 -size <n> # 默认单位是块(512字节), 反对 k(KB), M(MB), G(GB), 能够用 + - 或无符号, 意义同下面的按工夫查找. 按归属 -user <user> # 按属主 -uid <uid> # 按属主的id 动作 -exec 操作 \; # 执行时无需确认, {} 作为转义字符会被替换成查找的文件 -ok 操作 \; # 相似 -exec, 然而每次操作都会提醒确认 运算符(按优先级从高到低排序) () # 强制优先 ! <表达式> # 逻辑非, 对<表达式>后果取反, 即不匹配前面条件, 比方 ! -name 示意不匹配指定文件名 -not <表达式> # 逻辑非, 同 ! <表达式> <表达式1> <表达式2> # 逻辑与(默认), 如果前一个<表达式>执行后果为false, 则不会执行后续<表达式> <表达式1> -a <表达式2> # 逻辑与, 同上 <表达式1> -and <表达式2> # 逻辑与, 同上 <表达式1> -o <表达式2> # 逻辑或 <表达式1> -or <表达式2> # 逻辑或 <表达式1> , <表达式2> # 前一个表达式的后果不影响后一个表达式的执行
cat
仅会批改 access 工夫
touch
会同时批改 access, modify, change
chmod
仅会批改 change 工夫
留神:
- 不同参数的前后程序很重要, 比方
-daystart
须要写在-atime
等之前, 否则对其不失效.
示例
# 仅删除昨天的日志find /path/to/log -daystart -mtime 1 -exec rm -v {} \;
grep 命令
文本内容过滤(查找)
查找文本中具备关键字的一行阐明 若未提供查找的文件名或是 - 则默认是规范输出语法 grep [选项] 模式 文件... grep [选项] (-e 模式 | -f 蕴含模式的文件) 文件... 选项 模式 -G, --basic-regexp # 应用根本正则(默认) -E, --extended-regexp # 应用扩大正则 -e 模式, --regexp=模式 # 当模式以 - 结尾时, 应应用这种形式 -v, --invert-match # 反向匹配, 只抉择不匹配的行 -i, --ignore-case # 疏忽大小写 -R, -r, --recursive # 递归地读每一目录下的所有文件。这样做和 -d recurse 选项等价。 显示内容 -A <n>, --after-context=<n> # 打印匹配行的后续 n 行 -B <n>, --before-context=<n> # 打印匹配行的后面 n 行 -o, --only-matching # 只显示匹配的局部(默认是显示匹配行的所有内容) -n, --line-number # 同时显示行号 批改显示类型, 不进行通常输入 -c # 打印匹配到多少行 -l, --files-with-matches # 打印匹配的文件名 -L, --files-without-match # 打印不匹配的文件名
留神:
- 在输出选项时尽量应用引号突围, 防止Shell去解释, 比方
grep \.
实际上模式是.
也就是匹配任意字符. 而grep "\."
或grep '\.'
才是匹配模式\.
在根本正则表达式中,元字符 ?, +, {, |, (, 和 ) 丢失了它们的非凡意义;作为代替,应用加反斜杠的 (backslash) 版本 ?, +, {, |, (, 和 ) 。
cut 行切割
在文件的每一行提取片段cut 选项 [FILE]...选项 -d, --delimiter <分隔> # 以指定分隔符来切割, 分隔符必须是单个字符 -f, --fields <list> # 输入指定地位的字段, 用逗号分隔多个地位, 地位从1开始
uniq 间断反复行解决
删除排序文件中的"间断"反复行 默认从规范输出读取, 输入到规范输入uniq 选项 [INPUT [OUTPUT]]选项 -c, --count # 在首列显示反复数量 -d, --repeated # 仅显示反复的行
sort 排序
对文本文件的行排序sort 选项 [FILE]...选项 字段类型 -n # 依照数值排序, 默认蕴含 -b -k # -r # 逆向排序 -b # 疏忽结尾的空格
seq 产生数字序列
产生数字序列语法 seq [OPTION]... LAST seq [OPTION]... FIRST LAST seq [OPTION]... FIRST INCREMENT LAST
tac 倒序显示
tac [选项] <文件=STDIN>
行编辑器
非交互式, 基于行操作的模式编辑.
sed 行编辑器
sed 是单行文本编辑器, 非交互式.
sed 的模式空间, 其根本工作形式
- 将文件以行为单位读取到内存(称作模式空间)
- 应用sed的每个脚本顺次对该行进行操作
- 打印模式空间的内容并清空
- 读取下一行, 反复执行上述步骤
sed 的空间示意图:
- 模式空间的内容默认会输入, 并清空
- 放弃空间的默认内容是
\n
Tip
- 应用
;
能够替换多个-e
模式空间 pattern space
s 替换命令
替换sed [选项] '[<寻址>]s<分隔符><old><分隔符><new><分隔符>[<标记位>]' [文件...] # 简略示例: sed 's/old/new/'参数 old # 反对正则表达式 分隔符 # 能够采纳 / 也能够采纳其余来防止与正则匹配内容抵触, 比方 ~ @ 等寻址(默认是所有行) ! # 对寻址取反, eg. "2,4!d" 示意不删除2~4行 <n> # 只替换第<n>行 <n1>,<n2> # 区间: 从<n1>到<n2>这几行 eg. /12\/Apr\/2020/,/13\/Apr\/2020/ 正则同样能够应用这种区间寻址 1,<n> # 替换从开始到第<n>行 <n>,$ # 替换从第<n>到完结的这些行 /正则/ # 仅替换合乎此正则匹配到的行 # eg. sed '/正则/s/old/new/' # eg. sed '/正则/,$s/old/new/' (正则能够和行号混用)示意从匹配到的正则那行开始到完结都替换 # 寻址能够匹配多条命令, 留神大括号. eg. /regular/{s/old/new/;s/old/new/} # 比方nginx日志须要筛选出 14号这天的: sed -n '/14\/Apr\/2020/,/15\/Apr\/2020/ p' xx.log 标记位(默认是只替换第1个匹配项) /g # 替换所有匹配项(默认只替换第1个匹配项) /<n> # <n>是一个数字, 示意每行只替换第<n>个匹配项 /p # 打印模式空间的内容(即匹配的行), 通常会和 -n 一起应用, 如果不和 -n 一起应用, 会导致匹配的行多输入顺次. # eg. sed -n 's/old/new/p' # 此时仅打印匹配的行 /w <file> # 将模式空间的内容(即匹配到的行)写入到指定文件选项 -r, --regexp-extended # 应用扩大正则表达式, 包含圆括号分组及回调. -e script, --expression=script # 指定多个执行脚本时, 每个脚本前用一个 -e. 能够应用 "分号" 简写 # Eg. -e 's/old1/new1/' -e 's/old2/new2/' -f script-file, --file=script-file # 加载脚本文件 -i[<后缀>], --in-place[=<后缀>] # 批改原始文件, 当指定后缀时则会生成对应的备份文件. 也能够间接输入重定向输入到其余文件 -n, --quiet, --silent # 默认不主动打印示例 # 应用扩大正则表达式 sed -r 's/old/new/' [文件]... # 执行多个脚本 sed -e 's/old/new/' -e 's/old/new/' [文件]... sed 's/old/new/;s/old/new/' # 应用分号隔开不同脚本 # 将后果写回文件保留 sed -i 's/' sed -i,.bak 's/' # 圆括号分组及回调 echo "a213123t" | sed -r 's/a(\d*)/b\1/g' # b213123t
d 删除命令
删除以后"模式空间的内容", 并放弃前面的命令, 读取新的内容并从新执行sed 扭转脚本的控制流, 读取新的输出行 (因为模式空间的内容被删除了, 因而d前面的脚本没法执行, 会略过) (应用 s 替换成空内容, 但实质上这一行内容还在, 依旧会执行后续脚本, 会输入)sed '[<寻址>]d' [文件...]寻址 同 s 命令示例 sed '1d' # 删除第一行 sed '/^\s*#/d' # 删除 # 结尾的行
a 追加命令
在匹配行的下一行插入内容sed '[<寻址>]a <插入内容>'示例 sed '1i haha' # 在原先第1行后面插入 haha
i 插入命令
在匹配行在上一行插入内容sed '[<寻址>]i <插入内容>'示例 sed '2i haha' # 在原先第二行后面插入 haha
c 改写命令
将匹配行替换成指定内容 指定匹配间断几行时, 只会替换1次 # sed '2,5c <替换内容>'sed '[<寻址>]c <替换内容>'示例 sed '2c hehe' # 将第2行替换成 "hehe"
r 读文件并插入 (从文件读取改写内容)
在匹配行上面别离插入指定文件中的内容sed '[<寻址>]r <文件名>'示例 sed '$r afile' bfile > cfile # 将 afile 内容追加到 bfile 结尾并合并成新的文件 cfile
罕用于合并多个文件
w 写文件 ?
?sed '[<寻址>]w <文件名>'
p 打印
与 替换命令 s 的标记位 /p
不一样.
输入匹配的行(不禁止原始的输入)sed [选项] '[<寻址>]p'示例 sed -n '<寻址>p' # 只打印匹配的行
n 提前读入下一行, 并指向下一行
sed 'n'示例 cat <<EOF | sed 'n' 1 2 3 4 5 EOF # 输入(因为未作任何操作, 因而原样输入) 1 2 3 4 5 # ---------------------- cat <<EOF | sed -n 'n;p' 1 2 3 4 5 EOF # 输入 2 4
失常模式
应用n命令后
应用n命令后
图起源: https://blog.51cto.com/studyi...
q 退出命令
遇到匹配项, 在解决完该项后退出sed '[<寻址>]q'示例 sed '2q' # 在打印完第二行后退出 sed '/root/q' # 在匹配到某一行有 root 后退出
打印前N行的一个比拟
sed 10q filename
读取前10行就退出sed -n '1,10p' filename
逐行读入全副, 只显示1-10行, 更耗时.
= 打印行号
打印出以后行号(单行显示) 不影响失常的打印sed '='示例 echo 'a' | sed '=' # 打印后果, 第一行 "1", 第二行 "a"
多行模式空间 pattern space
多行模式空间扭转了 sed 的根本流程, 通过应用 N, P, D 读入并解决多行.
次要应答配置文件是多行的状况, 比方 json 或 xml.
综合示例
a.txt 内容如下123456789# ------------------- 示例1 ---------------------#sed 'N;N;s/\n/\t/g;' a.txt1 2 34 5 67 8 9# ---------------------示例2 打印梯形构造 -------------------## 关键在于利用 D 扭转控制流sed -n 'P;N;s/\n/\t/;s/^/\n/;D' a.txt11 21 2 31 2 3 41 2 3 4 51 2 3 4 5 61 2 3 4 5 6 71 2 3 4 5 6 7 81 2 3 4 5 6 7 8 9
b.txt 内容如下hello bash hello bash# -------------------- 示例 hello bash 替换成 hello sed --------------#sed 's/^\s*//;N;s/\n//;s/hello bash/hello sed\n/;P;D;' b.txthello sedhello sed
N 将下一行退出到模式空间
读取时, 将下一行退出到模式空间 两行视为同一行, 但两头有个换行符 \n 此时多行模式 . 能够匹配到除了开端的其余换行符sed 'N'示例 sed = <文件> | sed 'N;s/\n/\t/' # 在每行后面退出行号
应用N命令后
图起源: https://blog.51cto.com/studyi...
D 删除模式空间中的第一个字符到第一个换行符
留神 会扭转控制流, 不再执行紧随的后续命令, 会再次回到脚本的初始处(但不清空模式空间)sed 'D'
P 打印模式空间中的第一个字符到第一个换行符
留神 仅仅是打印, 并不会删除打印的局部.sed 'P'
放弃空间 hold space
留神:
放弃空间在不存储货色时, 它外面的默认内容是
\n
因而第一次个别是用
h
笼罩掉放弃空间的\n
- 放弃空间的内容只能长期存储和取出, 无奈间接批改
综合示例
# 下述多个都实现了 tac 倒序显示的成果# 思路: 每次将本轮正确的后果保留在放弃空间cat -n /etc/passwd | head -n 6 | sed -n '1!G;$!x;$p'cat -n /etc/passwd | head -n 6 | sed -n '1!G;h;$p'cat -n /etc/passwd | head -n 6 | sed '1!G;h;$!d'cat -n /etc/passwd | head -n 6 | sed '1!G;$!x;$!d'cat -n /etc/passwd | head -n 6 | sed -n '1h;1d;G;h;$p';cat -n /etc/passwd | head -n 6 | sed -n '1h;1!G;h;$p';sed '=;6q' /etc/passwd | sed 'N;s/\n/\t/;1!G;h;$!d'# --------------------- 显示后果 --------------------#6 sync:x:5:0:sync:/sbin:/bin/sync5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin4 adm:x:3:4:adm:/var/adm:/sbin/nologin3 daemon:x:2:2:daemon:/sbin:/sbin/nologin2 bin:x:1:1:bin:/bin:/sbin/nologin1 root:x:0:0:root:/root:/bin/bash
h 和 H 将模式空间内容寄存到放弃空间
- h 是笼罩
- H 是追加
留神: 该操作不会清空模式空间(须要清空模式空间能够用 d
)
g 和 G 将放弃空间内容取出到模式空间
- g 是笼罩
- G 是追加
留神: 该操作不会清空放弃空间
x 替换模式空间和放弃空间内容
awk 行编辑器
awk 是一种解释型编码语言, 罕用于解决文本数据.
awk 次要是对 sed 的一个补充, 罕用于在sed解决完后对相应后果进行调整并输入.
awk 版本
- awk: 初始版本
- nawk: new awk, 是 awk 的改良增强版
gawk: GNU awk, 所有 GNU/Linux 发行版都蕴含 gawk, 且齐全兼容 awk 与 nawk
理论 centos 用的就是 gawk
参考文档:
- The GNU Awk User's Guide
网上很多教程瞎JB写, 倡议以官网文档???? 为准
- 精通awk系列
十分不错的系列教程! :+1:
- https://awk.readthedocs.io/en...
不残缺.
awk 和 sed 的区别
- awk 更像是脚本语言
- awk 用于"比拟标准"的文本处理, 用于统计数量并调整程序, 输入指定字段.
- 应用 sed 将不标准的文本处理为"比拟标准"的文本
awk 脚本的流程管制
BEGIN{}
输出数据前例程, 可选{}
主输出循环END{}
所有文件读取实现例程
集体了解的执行程序
- 执行开始块(可选)
BEGIN{}
若存在主体块 {}
或完结块
END{}`, 则关上文件并读入数据如果文件无奈关上会在此时报错.
主体块容许存在多个, 比方依据不同的匹配模式, 写多个主体块.
- 若存在
<寻址>
或/pattern/
, 则会顺次匹配, 通过则对该记录执行{}
- 读完所有记录后, 执行完结块(可选)
END{}
非凡状况, 脚本只蕴含 BEGIN{}
时, 在执行 awk 命令前面传入参数(非文件名), 此时不会导致报错, 因为不会执行到步骤2(即尝试关上文件).
如果脚本只蕴含 BEGIN{命令}
, 如同能够缩写成 awk '命令'
??
语法
语法 awk [选项] 'awk脚本内容' [ -- ] [文件...] # 其中任意一部分都是可选的 awk [选项] -f <awk脚本文件> [ -- ] [文件...] # 不间接在命令行中书写 awk 脚本, 而是从指定文件读取选项 -f <脚本文件>, --file=<脚本文件> # 从指定脚本文件读取 awk 脚本, 而不是默认地从第一个命令行参数读取. -F, --field-separator <分隔符> # 字段分隔符能够应用正则表达式, 是空格 " ", 也能够在awk脚本中用 FS="," 来批改这一行为 -v <var>="val", --assign <var>="val" # 间接为awk脚本中的变量赋值, 比方 -v suffix=yjx, 而后代码中间接就存在 suffix 这个变量了, 且值是 yjx --dump-variables[=<file="awkvars.out">] # 将awk中的所有全局变量及其值导出到指定文件中. awk脚本的块 开始块 BEGIN {} # 非凡模式: 读取输出数据前 主体块 表达式 {} # 若匹配上才执行后续的 action # eg. # `$1 == "top" {}` # `NR >= 2 {}` # 'length($0)' /正则/ {} # 正则匹配, 若匹配上才执行后续的 action # eg. # /^menu/ 只解决 menu 结尾的记录 # /cost/ 只解决本行内容中蕴含 "cost" 的记录 !/正则/ {} # 正则不匹配 组合模式 {} # 一个 组合模式 通过与(&&),或(||),非(|),以及括弧来组合多个表达式 {} # 每读取一行数据则执行后续的 action 模式1,模式2 {} # 范畴模式(range pattern)匹配从与 模式1 相匹配的行到与 模式2 相匹配的行(蕴含该行)之间的所有行,对于这些输出行,执行 语句 。 完结块 END {} # 非凡模式: 读取结束后 主体块的action print 打印(若未配置则默认是 print) next 对于本行的解决, 跳过后续步骤表达式 {...} 执行 {} 中的脚本示例. awk [选项] 'BEGIN{} [<条件>] {} END{}' 文件... # 其中任意一部分都是可选的 # BEGIN{} 输出数据前例程 # {} 主输出循环, <寻址> 是利用于 {} 的 # END{} 所有文件读取实现例程 awk -f <脚本.awk> # 从文件中加载执行的命令, 留神<寻址>要和 { 写在同一行, 不然如同没失效? # 示例 xx.awk # BEGIN { # ... # } # /过滤条件/ { # ... # } # END { # ... # }字段援用 $0 # 示意记录整行 $1 $2 ... $n # 示意第1~第n个字段 NF # 标识 $0 被宰割的字段数 $NF # 示意最初一个字段, NF 变量示意字段的数量, 比方以后共5个字段, 则 $NF 等价于 $5. 简略示例 awk -F ',' '{print $1,$2,$3}' filename # 逗号分隔, 打印前3个字段 echo "menuentry 'CentOS Linux (5.5.6) 7 (Core)' --class centos" | awk -F "'" '{print $2}' # 提取出内核版本
批改字段或NF值的联动效应
留神以下几种操作
- 批改
$0
会依据FS
, 从新划分字段并主动赋值给$1
,$2
, ... ,NF
.$0=$0
也会触发从新划分字段的操作. 批改
$1
,$2
, ... , 会依据OFS
从新生成$0
, 但不会从新宰割.即便是
$1=$1
也会触发上述操作, 当然是用NF=NF
也是能够的.# 利用该个性从新生成去除行首行尾空格, 压缩两头空格的成果echo " a b c " | awk '{NF=NF; print $0;}'输入a b c
- 赋值给不存在的字段, 会新增字段并按需应用空字符串填充两头的字段,并应用
OFS
从新计算$0 - 减少
NF
值,将应用空字符串新增字段,并应用OFS
从新计算$0
- 缩小
NF
值,将抛弃肯定数量的尾部字段,并应用OFS从新计算$0
正则字面量
这里有个中央容易被坑到!!!
任何独自呈现的 /pattern/
都等价于 $0 ~ /pattern/
, 这个在将正则表达式赋值给变量时特地容易被坑, 举例:
if(/pattern/)
等价于if($0 ~ /pattern/)
a = /pattern/
等价于将$0 ~ /pattern/
的匹配返回值(0或1)赋值给 a/pattern/ ~ $1
等价于$0 ~ /pattern/ ~ $1
,示意用$1
去匹配0或1/pattern/
作为参数传给函数时,传递的是$0~/pattern/
的后果0或1
匹配胜利时返回1, 失败返回0.
举例
# 这边间接用于匹配没什么问题awk 'BEGIN { if ("abc" ~ "^[a-z]+$") { print "match"} }'#输入matchawk 'BEGIN { if ("abc" ~ /^[a-z]+$/) { print "match"} }'#输入match# 这边将其赋值给其余变量, 此时其实 regex = $0 ~ /^[a-z]+$/, 也就是值 0awk 'BEGIN { regex=/^[a-z]+$/; print regex; if ("abc" ~ regex) { print "match"} }'#输入0awk 'BEGIN { regex="^[a-z]+$"; print regex; if ("abc" ~ regex) { print "match"} }'#输入^[a-z]+$match
在 awk 中书写正则能够用 /[0-9]+/
也能够用
/[0-9]+/
匹配形式:"str" ~ /pattern/或"str" !~ /pattern/
匹配后果返回值为0(匹配失败)或1(匹配胜利)
任何独自呈现的/pattern/都等价于$0 ~ /pattern/
if(/pattern/)等价于if($0 ~ /pattern/)
坑1:a=/pattern/等价于将$0 ~ /pattern/的匹配返回值(0或1)赋值给a
坑2:/pattern/ ~ $1等价于$0 ~ /pattern/ ~ $1,示意用$1去匹配0或1
坑3:/pattern/作为参数传给函数时,传递的是$0~/pat/的后果0或1
坑4.坑5.坑6…
内置变量
awk 中能够看作是在一个独立的零碎空间中, 因而也有其非凡的零碎变量.
留神:
- 字段的援用不能加
$
, 这点与Shell不一样, 不然就变成获取记录中某个字段的值了.
管制 AWK 工作的预约义变量
FS
(field separator)输出数据的分隔符, 默认值是空格awk -F ","# 等价于awk 'BEGIN {FS=","}' # 在读入文件之前设置字段分隔符
OFS
(output field separator)输入字段分隔符(默认是空格)awk 'BEGIN {OFS=","}'
FIELDWIDTHS
以指定宽度切割字段而非依照 FSFPAT
以正则匹配, 将匹配到的后果作为字段, 而非依照 FS 或 FIELDWIDTHS 划分. 了解为 re_match, 而不是 re_splitFPAT = "([^,]+)|(\"[^\"]+\")"# 上述 FPAT 用于宰割以逗号分隔的 csv 文件, 若应用双引号包裹的则视为是一个字段(疏忽其中的逗号).# 比方对于数据: abc,"pqr,mno"# $1 值为 abc# $2 值为 "pqr,mno"
https://stackoverflow.com/que...
RS
(record separator)记录宰割符(默认是\n
)该变量通常在 BEGIN 块中批改, 批改该变量能够管制 awk 每次读取的数据的范畴(默认是读取一行), 读取到的记录是不蕴含记录分隔符的.
- RS 设置为单个字符: 间接应用该字符来宰割记录
- RS 设置为多个字符: 视为正则(非兼容模式), 应用该正则来宰割记录.
awk 'BEGIN {RS=":"}' # 将记录宰割符设置为 : , 这样每次遇到 : 时就视为一条记录别离解决.
非凡读取需要
RS=""
: 按段落读取(这个个性有用)RS="\0"
: 一次性读取所有数据, 但有些非凡文件蕴含了空字符\0
RS="^$"
: 真正的一次性读取所有数据, 因而^$
匹配的是空文件RS="\n+"
: 按行读取, 但疏忽空行
ORS
(output row separator) 输入记录分隔符(默认是\n
)awk 'BEGIN {OFS=":"}'
CONVFMT
示意数据转换为字符串的格局, 默认值是%.6g
OFMT
示意数值输入的格局, 默认值是%0.6g
, 标识无效位(整数局部加小数局部)最多为6.IGNORECASE
管制是否对大小写敏感, 当该变量设置时, 疏忽大小写. 在宰割记录时也受该变量影响.awk 'BEGIN{IGNORECASE=1} /amit/' marks.txt
携带信息的预约义变量
文件与行号
FILENAME
以后被解决的文件名在
BEGIN {}
块中, 该变量是未定义的.NR
(number of rows)记录的行号会始终累加, 就算解决多个文件, 该行号也会始终累加.
FNR
(file number of rows)记录的行号(解决不同文件时会重置)当解决多个文件时, 切换到不同文件则该值会重置掉.
NF
(number of fields)字段数量最初一个字段内容能够用 $NF 取出
ARGIND
用于解决多个文件时, 示意以后正在解决的文件的程序(从 1 开始)awk 'ARGIND==1 {if(FNR>3)print FNR,$3 } ARGIND==2 {if(FNR>1)print FNR,$2} ARGIND==3 {if(FNR<3)print FNR,$NF}' s.log t.log s.log
RT
(Record Termination) 理论记录宰割符当 RS 设置为多个字符(正则)时, 在每条记录被读取并宰割后,
RT
变量会被设置为理论用于划分记录的字符.
命令行与环境参数
ARGC
命令行地位参数个数("选项"是不蕴含在内的)ARGV
命令行地位参数数组ARGV[0]
值是命令名自身, 即awk
ARGV[1]
是传入的第1个参数- 范畴:
ARGV[0]
~ARGV[ARGC - 1]
ENVIRON
寄存零碎环境变量的关联数组awk 'BEGIN{print ENVIRON["USER"]}' # 输入: shell 变量 "USER"
PROCINFO
关联数组, 保留过程相干的信息# 打印 awk 过程的Idawk 'BEGIN { print PROCINFO["pid"] }'
ERRNO
用于存储当 getline 重定向失败或 close 函数调用失败时的失败信息.
表达式
赋值操作符
=
=
的左右是能够有空格的.- 字符串拼接中的空格会被疏忽
Eg.
var = "hello" "world"
实际上 var 值是
"helloworld"
, 没有两头的空格 - 若是拼接两个字符串变量, 则应用字符串字面量隔开即可.
s3=s1""s2
++
反对前置递增和后置递增
--
反对前置递加增和后置递加
+=
-=
*=
/=
%=
^=
算数操作符
+
-
*
/
%
^
位操作
AND
按位与操作OR
按位或操作XOR
按位异或操作
关系操作符
<
>
<=
>=
==
留神, 判断两个值是否相等要用
==
, 而不是赋值运算符=
!=
~
字符匹配正则表达式!~
布尔操作符
&&
||
!
应用
!
时留神应用括号将相干表达式括起来, 防止写错.
三元运算符
condition expression ? statement1 : statement2
匹配运算符
除了块的条件匹配外, 还能够用于 if
判断之类的.
~
匹配指定正则表达式的, 用于主体块的条件匹配# 仅解决蕴含 hello 文本的行awk '$0 ~ "hello"' xx.txt# 留神这里正则是用 / / 包围起来, 而不是双引号awk 'BEGIN { if ("[abc]" ~ /\[.*\]/) { print "match";}}'#输入#match# 留神这里用双引号括起来时, 外面用了双斜杠来解决正则的 [awk 'BEGIN { if ("[abc]" ~ "\\[abc\\]") { print "match";}}'#输入#match
!~
不匹配指定正则表达式的, 用于主体块的条件匹配# 仅解决不含 hello 文本的行awk '$0 !~ "hello"' marks.txt
条件和循环
留神:
表达式后果: 0为false, 1为true
这个与 Shell 是相同的.
- 影响管制的语句:
break
,continue
综合示例
cat kpi.txtuser1 70 72 74 76 74 72user2 80 82 84 82 80 78#-------------- 计算每行数值的总之和平均值 -----------#awk '{total=0; avg=0; for (i=2;i<=NF;i++) {total+=$i;} avg=total/(NF-1); print $1,total,avg;}' kpi.txtuser1 438 73user2 486 81
if 条件语句
if (表达式) {} else if (表达式) {} else {}
执行多条语句要用 {}
, 只有一条语句时可疏忽.
for 循环
for (初始值; 循环判断条件; 累加) {}
while 循环
while (表达式) {}
do 循环
do {} while(表达式)
数组
一般数组
awk 的数组实际上是关联数组, 可通过下标(数字实际上也是字符串)顺次拜访
比方
arr[1]
和arr["1"]
实际上是对同一个 key 操作反对多维数组
gawk(能够认为是 awk 的加强版, 代替版, 至多 centos 的 awk 理论就是 gawk) 反对真正意义上的多维数组.
awk 还有一种更"原始"的应用一维数组模仿多维数组的, 但在 gawk 中曾经没必要了.
# 定义## 下标能够是数字(视为字符串)或字符串数组名[下标] = 值# 遍历for (变量 in 数组名) { 数组名[变量] # 获取对应数组值}# 删除数组delete 数组# 删除数组元素delete 数组[下标]# 判断数组中是否存在指定"键"if (key in array)# 判断数组中是否不存在指定"键", 留神这里额定加了一个括号, 不能省略了if (!(key in array))
命令行参数数组
ARGC
命令行地位参数个数ARGV
命令行地位参数数组ARGV[0]
值是命令名自身, 即awk
ARGV[1]
是传入的第1个参数- 范畴:
ARGV[0]
~ARGV[ARGC - 1]
示例
cat argv.awk内容 BEGIN { for (i=0; i<ARGC; i++) { print ARGV[i]; } print ARGC; }# --------------------------------#awk -f argv.awk afile 11 22 33输入 awk # ARGV[0] afile # ARGV[1] 11 # ARGV[2] 22 # ARGV[3] 33 # ARGV[4] 5 # ARGC
此处不会报错是因为awk脚本中只蕴含 BEGIN {}
局部, 因而不会将参数视为文件名并尝试关上.
数组函数
length(数组)
获取数组长度asort(数组a[, 数组b, ...])
对数组a的值进行排序,并且会丢掉原先键值(从新生成数字递增的 key 来代替), 并将后果赋予数组 b (若未传, 则间接批改数组 a).arorti(数组a[, 数组b, ...])
对数组a的键进行排序, 并将后果赋予数组 b (若未传, 则间接批改数组 a).
函数
算术函数
sin()
cos()
atan2(y,x)
exp(x)
返回自然数 e 的 x 次方sqrt()
平方根log(x)
计算 x 的自然对数int()
转换为整数(疏忽小数局部)rand()
伪随机数, 范畴[0,1)
, 默认应用srand(1)
初始化随机种子.若不应用
srand()
会发现每次获取的所谓随机数都是一样的.srand(); print rand();
srand([seed])
重置随机种子, 默认种子采纳以后工夫的 epoch 值(秒级别)
位操作函数
compl(num)
` 按位求补lshift(num, offset)
左移N位rshift(num, offset)
右移N位
字符串函数
awk 中波及字符索引的函数, 索引位都是从 1 开始.
留神, 不同 awk 版本, 函数参数个数是有可能不一样的.
sprintf(format, expr1, ...)
返回格式化后的字符串示例:
a = sprintf("%10s\n", "abc")
length(s)
返回字符串/数组的长度strtonum(str)
将字符串转换为十进制数值如果 str 以0结尾,则将其辨认为8进制
如果 str 以0x或0X结尾,则将其辨认为16进制
tolower(str)
转换为小写toupper(str)
转换为大写查找
index(str,substr)
在指标字符串中查找子串的地位, 若返回 0 则示意不存在.match(string, regexp, array)
字符串正则匹配, 将匹配后果保留在 arr 数组中.变量
RLENGTH
示意 match 函数匹配的字符串长度.变量
RSTART
示意 match 函数匹配的字符串的第一个字符的地位.awk 'BEGIN { if (match("One Two Three", "re")) { print RLENGTH } }' # 输入 2awk 'BEGIN { if (match("One Two Three", "Thre")) { print RSTART } }' # 输入 9
cat test# this is wang,not wan# that is chen,not che# this is chen,and wang,not wan cheawk '{match($0, /.+is([^,]+).+not(.+)/, a); print a[1],a[2]}' test# wang wan# chen che# chen wan che
替换
gsub(regx,sub [,targe=$0])
全局替换, 会间接批改原始字符串, 返回替换胜利的次数.如果
target
应用$0
,$...
等, 那么替换胜利后会应用 OFS 从新计算$0
这边
sub
不反对反向援用, 只能应用&
来援用匹配胜利的局部sub(regx,sub [,targe=$0])
只替换第一个匹配的, 会间接批改原始字符串, 返回替换胜利的次数.gensub(regx, sub [, how [, target]])
不批改原字符串, 而是返回替换后的字符串. 能够齐全代替gsub
和sub
how
: 指定替换第几个匹配, 比方 1 示意只替换第一个匹配,g
或G
示意全局替换这是 gawk 提供的函数, 其中
sub
反对应用\N
援用分组匹配, 或&
,\0
来标识匹配的整个后果.awk 'BEGIN { a = "111 222" b = gensub(/(.+) (.+)/, "\\2 \\1, \\0, &", "g", a) print b}'# 输入222 111, 111 222, 111 222
截取
substr(str,pos,num=残余所有)
从指定地位开始截取一个子串
宰割
split(str, arr [, 正则分隔符=FS])
字符串宰割为数组, 并将其保留到第2个参数中, 函数返回值是宰割的数patsplit(str, arr[, 正则分隔符=FPAT])
应用正则捕捉匹配的字符串, 并将其保留到第2个参数中.
若不分明的, 能够在 man awk
中搜寻相应关键字
工夫函数
systime
返回以后工夫戳(秒级)mktime("YYYY MM DD HH mm SS [DST]")
依据给定的字符串格局, 返回其对应的工夫戳# 格局: 年 月 日 时 分 秒awk 'BEGIN{print mktime("2020 10 10 17 51 59")}'
strftime([format [, timestamp[, utc-flag]]])
将工夫戳(默认是以后工夫)转换为字符串示意awk 'BEGIN {print strftime("Time = %Y-%m-%d %H:%M:%S")}'输入Time = 2020-10-12 17:53:37
SN 形容 %a 星期缩写(Mon-Sun)。 %A 星期全称(Monday-Sunday)。 %b 月份缩写(Jan)。 %B 月份全称(January)。 %c 本地日期与工夫。 %C 年份中的世纪局部,其值为年份整除100。 %d 十进制日期(01-31) %D 等价于 %m/%d/%y. %e 日期,如果只有一位数字则用空格补齐 %F 等价于 %Y-%m-%d,这也是 ISO 8601 规范日期格局。 %g ISO8610 规范周所在的年份模除 100(00-99)。比方,1993 年 1 月 1 日属于 1992 年的第 53 周。所以,尽管它是 1993 年第 1 天,然而其 ISO8601 规范周所在年份却是 1992。同样,只管 1973 年 12 月 31 日属于 1973 年然而它却属于 1994 年的第一周。所以 1973 年 12 月 31 日的 ISO8610 规范周所在的年是 1974 而不是 1973。 %G ISO 规范周所在年份的全称。 %h 等价于 %b. %H 用十进制示意的 24 小时格局的小时(00-23) %I 用十进制示意的 12 小时格局的小时(00-12) %j 一年中的第几天(001-366) %m 月份(01-12) %M 分钟数(00-59) %n 换行符 (ASCII LF) %p 十二进制表示法(AM/PM) %r 十二进制表示法的工夫(等价于 %I:%M:%S %p)。 %R 等价于 %H:%M。 %S 工夫的秒数值(00-60) %t 制表符 (tab) %T 等价于 %H:%M:%S。 %u 以数字示意的星期(1-7),1 示意星期一。 %U 一年中的第几个星期(第一个星期天作为第一周的开始),00-53 %V 一年中的第几个星期(第一个星期一作为第一周的开始),01-53。 %w 以数字示意的星期(0-6),0示意星期日 。 %W 十进制示意的一年中的第几个星期(第一个星期一作为第一周的开始),00-53。 %x 本地日期示意 %X 本地工夫示意 %y 年份模除 100。 %Y 十进制示意的残缺年份。 %z 时区,示意格局为+HHMM(例如,格局要求生成的 RFC 822或者 RFC 1036 工夫头) %Z 时区名称或缩写,如果时区待定则无输入。
其余函数
getline
请参照下方的 "getline" 局部.
close(xxx [, from|to])
敞开文件、shell过程, 能够仅敞开某一端.
close(xxx, "to")
示意敞开该管道的写入端,close(xxx, "from")
示意敞开该管道的输入端.留神!!!! awk 中任何文件都只会在第一次应用时关上, 之后都不会再从新关上(而是从上次的读取地位持续). 因而只有在敞开之后, 再次应用时才会从新关上.
next
跳过对以后记录的后续解决.会回到 awk 循环的头部, 读取下一行.
nextfile
进行解决以后文件, 从下一个文件开始解决.return xx
函数返回值system("shell命令")
执行 shell 命令, 并返回退出的状态值, 0示意胜利.flush([output-expr])
刷新关上文件或管道的缓冲区如果没有提供 output-expr,fflush 将刷新规范输入。若 output-epxr 是空字符串 (""),fflush 将刷新所有关上的文件和管道。
close(expr)
敞开文件句柄 ???awk 'BEGIN { cmd = "tr [a-z] [A-Z]" print "hello, world !!!" |& cmd # "&|" 示意双向管道通信 close(cmd, "to") # 敞开其中一个方向的管道, 另一个是 "from" 方向 cmd |& getline out # 应用 getline 函数将输入存储到 out 变量中 print out; close(cmd); # 敞开管道}'输入HELLO, WORLD !!!
exit <code=0>
终止脚本
自定义函数
function 函数名(参数) { awk 语句 return awk变量}
留神
- 自定义函数的书写不能再
BEGIN{}
,{}
,END{}
的里层
getline
getline 函数用于读取一行数据.
依据不同状况, 返回值不一样.
- 若读取到数据, 返回 1.
- 若遇到 EOF, 返回 0.
- 产生谬误, 返回正数. 如-1示意文件无奈关上,-2示意IO操作须要重试(retry)。在遇到谬误的同时,还会设置 ERRNO 变量来形容谬误.
awk '{print $0; getline; print $0}' marks.txt # 倡议应用 getline 时判断一下是否读取胜利awk 'BEGIN {getline; if ((getline) > 0) {...}}'
从以后文件读取
- 应用
getline
不带参数时, 示意从以后正在解决的文件中立刻读取下一条记录并保留到$0
, 同时进行字段宰割(别离存到$1
,$2
,...), 同时会设置 NF, RT, NR, FNR, 而后继续执行后续代码. - 执行
getline <变量名>
时, 会将读取后果保留到对应变量中, 而不会更新$0
, 也不会更新 NF,$1
,$2
, ..., 此时仅仅会更新 RT, NR, FNR.
从其余文件读取
执行
getline < "filename"
示意从指定文件读取一条记录并保留到$0
中(同时进行字段宰割), 及 NF. 至于 NR, FNR 则不会更新.每次读取记录后会自动记录读取的地位.
配合
while
及getline
的返回值能够遍历完文件.留神
getline < abc
与getline < "abc"
是两码事, 一个是从 abc 变量指向的文件读取, 一个是读取 abc 文件- 执行
getline 变量名 < "filename"
示意从指定文件读取一条记录并保留到指定变量中.
从 shell 命令输入后果中读取
cmd | getline
:从Shell命令cmd
的输入后果中读取一条记录保留到$0
中会进行字段划分,设置变量
$0
NF
$N
RT
,不会批改变量NR
FNR
cmd | getline var
:从Shell命令cmd
的输入后果中读取数据保留到var
中除了
var
和RT
,其它变量都不会设置
如果要再次执行 cmd 并读取其输入数据,则须要close敞开该命令, 示例:。
# 若屏蔽下方的 close 函数, 则再次读取该 cmd 时为空. 因而须要敞开先.awk 'BEGIN {cmd = "seq 1 5"; \while((cmd | getline) > 0) {print}; \close(cmd); \while((cmd | getline) > 0) {print}; \}'
能够不便地应用 shell 给 awk 中变量赋值
awk 'BEGIN {get_date = "date +\"%F %T\""; \get_date | getline cur_date; \print cur_date; \close(get_date);}'输入2020-10-13 19:14:17
将数据传给 shell 解决完(coprocess), 再读取
这里要利用 coprocess, 也就是 |&
操作符.
awk 能够利用 |&
将一些不好解决的数据传给 shell 来解决后, 再从 shell 中读取后果, 持续在 awk 中解决.
应用 shell 的排序功能
# sort 命令会期待数据写入结束后(即 EOF 标记)才开始排序, 因而理论是在执行 close(CMD, "to") 时才开始执行.awk 'BEGIN {CMD = "sort -k2n";print "6 66" |& CMD;print "3 33" |& CMD;print "7 77" |& CMD;close(CMD, "to");while ((CMD |& getline) > 0) { print;}close(CMD);}'输入:3 336 667 77
应用留神:
awk-print |& cmd
会间接将数据写进管道, cmd 能够从管道中获取数据- 强烈建议在awk_print写完数据之后加上
close(cmd,"to")
,这样示意向管道中写入一个EOF标记,防止某些要求读完所有数据再执行的cmd命令被永恒阻塞.敞开管道另一端能够应用
close(cmd, "from")
- 如果
cmd
是按块缓冲的,则getline
可能会陷入阻塞。这时可将cmd
局部改写成stdbuf -oL cmd
以强制其按行缓冲输入数据CMD="stdbuf -oL cmdline";awk_print |& CMD;close(CMD,"to");CMD |& getline
高级输入
print 输入重定向
print "..."
print "..." > 文件名
重定向输入print "..." >> 文件名
重定向输入这玩意比应用
system
函数再调用 echo 快了好几个量级print "..." | "shell 命令"
awk 将创立管道, 并启动 shell 命令. print 产生的数据放入管道, shell 命令则从管道中读取数据.print "..." |& "shell 命令"; "shell 命令" | getline
和下面的|
不同之处在于, 这里是将数据交给 Coprocess, 之后 awk 还须要再从 Coprocess 取回数据.Coprocess 执行 shell 命令的时候, 后果是不输入到规范输入的, 而是须要从管道中自行读取.
反对重定向到
- 规范输出
/dev/stdin
- 规范输入
/dev/stdout
- 规范谬误
/dev/stderr
若 print 输入后发现后续的管道命令没有内容, 那其实是因为 awk 的输入存在缓存, 可应用 fflush()
函数刷新缓冲区.
对于 |
和 |&
应用上区别的示例
# 这里用的是 |, 执行后果间接输入到规范输入awk 'BEGIN {cmd = "tr \"[a-z]\" \"[A-Z]\""print "hello" | cmd> }'# 这里用的是 |&, 执行后果须要手动从 Coprocess 管道读取awk 'BEGIN { cmd = "tr \"[a-z]\" \"[A-Z]\"" print "hello" |& cmd; close(cmd, "to"); cmd |& getline line; print line; close(cmd);}'输入HELLO
printf 格式化
printf(format, value1, value2, ...)参数 format 格局 %c (将ASCII转换为)字符 %s 字符串 %d,%i 整数 %e,$e 迷信计数法示意 %f,%F 浮点数 %g,%G 浮点数, 会移除对数值无影响的 0 %o 无符号八进制 %u 无符号十进制 %x,%X 无符号十六进制 %% 百分号 留神: 输入时不会主动换行 示例 printf("total pay for %s is $%.2f\n", $1, $2 * $3) # %-8s 字符串, 8个字符宽度, 左对齐 # %6.2f 浮点数, 6个字符宽度, 保留2位小数 printf("%-8s %6.2f\n", $1, $2 * $3)
参考: https://awk.readthedocs.io/en...若仅仅是为了格式化字符串(不输入), 能够用 sprintf 函数.
format 反对的转义序列
- 换行符
\n
- 程度制表符
\t
垂直制表符
\v
了解为输入光标垂直向下挪动一行
退格符
\b
了解为输入光标后退一格.
回车符
\r
了解为光标会回退到以后行的结尾(罕用于笼罩本行)
换页符
\f
这个成果...得试一下才行
format 的 %
的可选参数
宽度
只有当字段的宽度比要求宽度小时该标示才会无效, 默认应用空格字符填充.
printf("%10d", 1)输入 1
前导零
0
只有当字段的宽度比要求宽度小时该标示才会无效
awk 'BEGIN {printf("%010d", 1)}'输入0000000001
左对齐
-
在
%
和数字之间应用-
符号即可指定左对齐awk 'BEGIN {printf("%-10d", 1)}'输入1
符号前缀
+
应用
+
, 在输入数字时, 将其正负号也输入.awk 'BEGIN {printf("%+10d", 1)}'输入 +1
保留进制标识
#
awk 'BEGIN {printf("%#o %#X\n", 10, 10)}'输入012 0XA
Examples
打印出以后的可用内核列表
并显示序号
awk -F "'" '/^menuentry/ {print x++,$2}' /boot/grub2/grub.cfg输入0 CentOS Linux (5.5.6) 7 (Core)1 CentOS Linux (3.10.0-1062.12.1.el7.x86_64) 7 (Core)2 CentOS Linux (3.10.0-957.el7.x86_64) 7 (Core)3 CentOS Linux (0-rescue-d64aa77b8f014365aa6557986697df9c) 7 (Core)
统计以后tcp的各个状态及数量
netstat -ntp | awk '/^tcp / {S[$6]++} END{for (i in S) print i,S[i];}'输入TIME_WAIT 108ESTABLISHED 154
统计每个接口的拜访工夫
time cat 20_10_*.txt | grep "request cost" | gawk -v suffix=_test -f ../stat_method.awk
stat_method.awk
BEGIN { DEBUG = 1 methodRecordFile = "method_record"suffix".csv" methodStatsFile = "method_stats"suffix".csv" if (DEBUG) { methodRecordFile = "/dev/stdout" methodStatsFile = "/dev/stdout" } print methodRecordFile print methodStatsFile}{ method=substr($10,2,length($10)-2) method=substr(method,1,length(method)-7) timeStr=$1" "$2 timeMs=$6 + 0.01 uid=substr($11,2,length($11)-2) msLevel=(int(timeMs/100) + 1) * 100 T[method][msLevel]++ if (!(method in Stats)) { Stats[method]["name"] = method Stats[method]["max"] = 0 Stats[method]["mean"] = 0 Stats[method]["count"] = 0 Stats[method]["sum"] = 0 Stats[method]["sumX2"] = 0 Stats[method]["min"] = 9999999999999 } if (timeMs > Stats[method]["max"]) { Stats[method]["max"] = timeMs } if (timeMs < Stats[method]["min"]) { Stats[method]["min"] = timeMs } Stats[method]["sumX2"] += timeMs * timeMs Stats[method]["count"]++ Stats[method]["sum"] += timeMs if (NR % 10000 == 0) { print "已解决 "NR" 条记录" }}END { print "----------- 总共解决 "NR" 条记录 -----------" print "method,msLevel,count" > methodRecordFile # print "method,msLevel,count" for (m in T) { for (l in T[m]) { print m","l","T[m][l] >> methodRecordFile # print m","l","T[m][l] } } print "----------- done -----------" print "method,min,max,mean,sd(标准差),count,sum(秒)" > methodStatsFile printf("%-30s\tmin\tmax\tcount\tmean\tsd(标准差)\t,sum(秒)\n", "method") for (m in Stats) { Stats[m]["mean"] = Stats[m]["sum"] / Stats[m]["count"] Stats[m]["sd"] = sqrt(Stats[m]["sumX2"] / Stats[m]["count"] - Stats[m]["mean"] * Stats[m]["mean"]) # for (n in Stats[m]) { # print "Stats["m"]["n"]= " Stats[m][n] # } print m "," Stats[m]["min"] "," Stats[m]["max"] "," Stats[m]["mean"] "," Stats[m]["sd"]"," Stats[m]["count"]","Stats[m]["sum"]/1000 >> methodStatsFile printf("%-30s\t%.2f\t%.2f\t%.0f\t%.2f\t%d\t%.2f\n", substr(m, 0, 30), Stats[m]["min"], Stats[m]["max"],Stats[m]["mean"],Stats[m]["sd"], Stats[m]["count"], Stats[m]["sum"]/1000) } print "----------- done -----------" print methodRecordFile print methodStatsFile}
格式化空白
cat > a.txt <<'EOF' aaaa bbb ccc bbb aaa cccddd fff eee gg hh ii jjEOFawk 'BEGIN{OFS=" "} {NF=NF; print}' a.txt
输入
aaaa bbb cccbbb aaa cccddd fff eee gg hh ii jj
打印 ini 文件中的某一段
awk -v scope="extras" 'BEGIN {scope="["scope"]"} $0 == scope { print; while ((getline) > 0) { if ($0 !~ /\[.*\]/) { print $0; } else { exit } }}' /etc/yum.repos.d/CentOS-Base.repo
输入如下 ????
[extras]name=CentOS-$releasever - Extrasmirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/gpgcheck=1gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7#additional packages that extend functionality of existing packages
解决字段中蕴含字段宰割符状况(csv)
echo 'Robbins,Arnold,"1234 A Pretty Street, NE","MyTown",MyState,12345-6789,USA' | awk 'BEGIN { FPAT="[^,]+|\"[^\"]+\"" } { print NF" "$3}'
输入如下 ????
7 "1234 A Pretty Street, NE"