Sed

sed [选项] '[地址]命令' 文件
选项
-n禁止自动打印,sed 每处理一行会自动打印一行,所以一般搭配 p 命令使用
-e多重命令,例如:sed -e 's/foo/bar/' -e 's/baz/qux/' file.txt
-i直接修改文件内容
-r-E使用扩展正则表达式
地址(行定位)
n第 n 行
n,m第 n 到 m 行
n,+m第 n 到 n+m 行
n~m从第 n 行开始,每隔 m 行匹配一次
$最后一行
/pattern/包含 pattern 的行,pattern 是正则表达式
/start/,/end/包含 start 的行到包含 end 的行
n,/end/第 n 行到包含 end 的行
!对地址取反,表示不匹配的行,例如:sed -i sed '1,3!d' file.txt 只保留 1 到 3 行,删除其它行
命令
s替换文本,格式:s/旧文本/新文本/[标志],标志:g 全局替换,i 忽略大小写,p 打印替换后的行
d删除行
p打印行
i在指定行上方插入新行及文本,如 sed '2i newline' file.txt
a在指定行下方插入新行及文本
c替换整行内容
=打印当前行行号

sed 脚本

#!/bin/sed -f
s/hello/HELLO/g
s/world/WORLD/g
$ chmod +x example.sed
$ ./example.sed file.txt
$ sed -f example.sed file.txt

Awk

awk [选项] '[表达式] { 语句1; 语句2; ... }' 文件
选项
-F指定分隔符(默认为空格或制表符),使用 $n 引用字段,$0 表示整个字段
-v定义变量,例如:awk -v var=123 '{print $1+var}' file.txt
表达式(行定位)
/pattern/包含 pattern 的行(正则匹配),例如:awk '/error/ { print $0 }' file.txt
$n ~ /pattern/第 n 列包含 pattern 的行
$n !~ /pattern/第 n 列不包含 pattern 的行
$n > 10第 n 列大于 10 的行,例如:awk '$1 > 10 { print $0 }' file.txt,还有 < <= > >= != ==
$n == "abc"第 n 列等于 abc 字符串的行
$n > 10 && $n < 20第 n 列大于 10 小于 20 的行,还有 ||
$1 + $2 > 10第 1、2 列的和大于 10 的行,还有 + - * / %

awk 脚本

awk 实际是一门编程语言,上面的只是在命令行的简单应用

更多内容参考:GNU awkMan gawk

内置变量 / 函数

变量
NF当前行的字段数
NR当前处理的行号
FS字段分隔符(默认空格或制表符),即命令行的 -F 选项,可在脚本中修改
OFS输出字段分隔符(默认空格),当 OFS=":"print $1,$2,$3 输出类似 a:b:c
RS记录分隔符(默认换行符),即一个换行符被 awk 识别为一行进行处理
ORS输出记录分隔符(默认换行符),即输出的每行末尾是换行符
函数
length(string)返回字符串的长度
tolower(string)转化为小写,还有 toupper
int(x)返回整数部分,还有 sqrt 平方根、log 对数等
systime()返回当前时间的时间戳
strftime(fmt, timestamp)将时间戳转化为格式化字符串,如 strftime("%Y-%m-%d %H:%M:%S", systime())
asort(array)对数组进行排序,并返回数组的长度

语句

所有语句都必须包含在 { }

多条语句使用 ; 分隔,或者另起一行

字符串使用 " " 包裹

BEGIN 和 END

BEGINEND 在处理第一行之前和最后一行之后执行一次,例如:

#!/bin/awk -f
BEGIN { count = 0 }
/error/ { count++ }
END { print "Total error:", count }

变量 / 数组 / 流程控制 / 函数

以下程序仅为语法示例,不能运行:

#!/bin/awk -f
BEGIN { 
    print "BEGIN" 
    i = 0
}

{
    # awk 的数组是无序的
    array[1] = "apple"
    array[2] = "banana"
    array["fruit"] = "orange"

    delete array[2]

    if ("banana" in array) {
        print "存在"
    } else {
        print "不存在"
    }

    for (i in array) {
        print "遍历数组", i, array[i]
    }

    for (i = 1; i <= n; i++) {
        print "跳过后面的语句"
        continue
        print "跳出当前循环"
        break
        print "跳过当前行,awk 是逐行处理文本的"
        next
        print "退出脚本"
        exit 0
    }

    while (i <= NF) {
        i++
    }

    switch ($1) {
        case "apple":
            print "It's an apple"
            break
        case "banana":
            print "It's a banana"
            break
        default:
            print "It's something else"
    }

    function add(a, b) {
        print "自定义函数"
        return a + b
    }
}

END { print "END" }

实例 - 统计 /etc/passwd

#!/bin/awk -f

BEGIN {
    print "开始统计用户数据"
    FS = ":"
    OFS = "\t"
    total = 0
}

{
    print "name="$1, "uid="$3, "gid="$4
    total++
}

END {
    printf "统计完毕,共 %d 名用户\n", total
}
$ chmod +x count.awk
$ ./count.awk /etc/passwd
开始统计用户数据
name=root       uid=0   gid=0
name=bin        uid=1   gid=1
....
name=avahi      uid=61  gid=61
统计完毕,共 23 名用户

Grep

grep [选项] '正则表达式' 文件
基本搜索
-i忽略大小写
-v反向匹配,输出不包含匹配字符串的行
-w匹配整个单词,如 grep -w 'word' file.txt 不会匹配 words
-x匹配整行,如 grep -x 'exact line' file.txt 只匹配完全等于 exact line 的行
输出控制
-c统计匹配的行数
-n显示匹配行的行号
-o只输出匹配的部分,而不是整行
-q静默模式,不输出任何内容,仅通过退出状态码表示是否匹配成功
文件操作
-r-R递归搜索目录中的文件,如 grep -r 'pattern' /path/to/dir
--include指定要搜索的文件类型,如 grep -r 'pattern' /path/to/dir --include '*.txt'
--exclude排除特定文件类型
-l输出文件中包含匹配字符串的文件名,如 grep -l 'pattern' *.txt输出包含 pattern.txt 文件名
-L输出文件中不包含匹配字符串的文件名
正则表达式
-E使用扩展正则表达式(等同于 egrep 命令);默认是基本正则表达式,不支持 + ? () {}
-F不解析正则表达式,视为普通字符串进行匹配
-P使用 Perl 兼容的正则表达式(PCRE),支持 \d \w \s
上下文控制
-A显示匹配行及其后面的 n 行,如 grep -A 2 'pattern' file.txt
-B显示匹配行及其前面的 n
-C显示匹配行及其前后各 n
其他选项
--color高亮显示匹配的部分
-e多重匹配,如 grep -e 'pattern1' -e 'pattern2' file.txt

Cut

cut 用于从文件或标准输入中提取指定的字符、字段

cut -d ':' -f 1 data.txt
选项
-d指定字段分隔符(默认以制表符 \t 为分隔符)
-f按字段提取,如 cut -f 1 data.txt 提取第一列,位置的表示方法有: 1,2,31-3
-s只输出包含分隔符的行,就不需要 grep 等命令过滤行了
-c按字符提取,如 cut -c 1-5 data.txt 提取每行的前 5 个字符
--complement提取除指定范围外的内容,如 cut -d ',' -f 1 --complement data.txt 提取除第一列外的所有列
--output-delimiter指定输出时的分隔符,如 cut -d ',' -f 1,3 --output-delimiter ':' data.txt

Tr

tr 用于转换或删除字符,如 echo "hello world" | tr 'a-z' 'A-Z' 输出 HELLO WORLD

tr [选项] 字符集1 字符集2
选项
-d删除字符集1中的字符,如 echo "hello 123 world" | tr -d '0-9 ' 输出 helloworld
-c使用不包含在字符集1中的字符(补集),如 echo "hello 123 world" | tr -cd 'a-z' 输出 helloworld
-s将字符集1中连续重复的字符压缩为单个字符,如 echo "goooood" | tr -s 'o' 输出 god
-t截断长的字符集,确保两个字符集长度一致,如 echo "abcdef" | tr -t 'abcdef' '123' 输出 123def

Tee

tee 的主要作用是将数据分流,既可以在屏幕上显示,又可以保存到文件中,如下:

echo "Hello, World!" | tee output.txt
选项
-a将数据追加到文件末尾,而不是覆盖文件
-i忽略中断信号(如 Ctrl+C

Sort

sort 用于对文件内容或标准输入进行排序操作

排序控制
-b忽略行首的空白字符
-d按照字典顺序排序,只考虑字母、数字和空白
-f忽略大小写
-g按照常规数值排序
-h按照人类可读的数字排序(如 2K, 1G)
-i忽略不可打印字符
-M按照月份名称(JAN, FEB等)排序
-n按照数值大小排序
-R随机排序
-r逆序排序
-V按照版本号排序
键定义
-k指定排序的键(字段)位置
-t指定字段分隔符
其他选项
-c检查文件是否已排序
-m合并已排序的文件
-o将结果输出到指定文件
-u去除重复行(相当于 uniq)
-z以 NUL 字符作为行结束符

Uniq

uniq 只能处理 连续的重复行,两条重复行之间隔了一条也不行,所以一般搭配 sort 命令使用

sort file.txt | uniq > unique.txt
选项描述
-c在每行前显示该行重复出现的次数
-d只显示重复的行(每组重复行只显示一次)
-D显示所有重复的行
-u只显示不重复的行
-i忽略大小写差异
-f N跳过前 N 个字段的比较,字段分隔符默认是空白字符(空格/Tab)
-s N跳过前 N 个字符的比较
-w N只比较每行的前 N 个字符

Wc

wc 用于统计文件中的行数、单词数和字节数

选项
-l统计行数
-w统计单词数
-c统计字节数

Tac

tac 用于将文件内容从最后一行按行逆序输出,与 cat 命令的功能相反