Linux-文本操作

wc

print newline, word, and byte counts for each file

  • wc -l [文件名] // 计算文件的行数
  • wc -c [文件名] // 计算文件字节数
  • wc -w [文件名] // 计算文件字符数

stat

display file or file system status

  • LANG=c stat [filename] // 英文化查看文件的信息

grep

print lines matching a pattern

  • grep [正则][文件名] 一行一行查找正则匹配的内容

find

search for files in a directory hierarchy

  • find *txt -exec rm -v {} ; // 查找文件并执行命令操作

time

计算指令的执行时间

  • time ls

cut

remove sections from each line of files

  • cut -d " " -f 1 // 以空格分隔文本并显示第一个(相当于 split()[0])

sed

默认只替换每行的第一个

sed 的工作模式

  • 将文件以行为单位读取到内存(模式空间)
  • 使用 sed 的每个脚本对该行进行操作 sed "script" filename
  • 处理完成后输出该行(默认输出)
sed 'a/lod/new/' filename

# 如果要替换/,可以使用别的分隔符
sed 's!/!abc!' filename

# 执行多个命令
sed -e 's/a/aa/' -e 's/aa/bb/' afile
sed 's/a/aa/;s/aa/bb/' afile

# 将替换后的内容写入到原始文件
sed -i 's/a/aa/;s/aa/bb/' afile

# 支持元字符
head -5 /etc/passwd | sed 's/s*bin//'

# 支持回调,源文件内容:axyzb
# 扩展元字符使用 -r 参数
root@4ebe31ff7a18:/tmp# sed -r 's/(a.*b)/\1:\1/' cfile
axyzb:axyzb

sed 替换指令加强版

  • 标志位:

    • s/old/new/ 标志位
# 全局替换
sed "s/old/new/g" afile

# 替换前两次
sed "s/old/new/2" afile

# /p 打印模式空间的内容,匹配的行在下面再进行输出,应用:只输出替换成功的行, -n阻止默认输出
sed -n 's/root/123/p'

# /w 将替换成功的行写入别的文件
sed -n 's/root/123/w a.txt'
  • 寻址:默认对每行进行操作,增加寻址后对匹配的行进行操作

    • /正则表达式/s/old/new/g
    • 行号/s/old/new/g
    • 可以使用两个寻址符号,也可以混合使用行号和正则地址
# 从1-6行进行替换
head -6 /etc/passwd | sed '1,6s/games/!!!!!!!!/'

# 匹配root行,进行替换
head -6 /etc/passwd | sed '/root/s/bash/!!!!!!!!/'

# 多条命令
sed /正则/{s/old/new/;s/old/new/}
  • 脚本文件:文件里写正常的 sed 命令
sed -f sedscript filename // 加载脚本文件

sed 的其他常用命令

# 删除行,删除操作会改变模式空间,就和管道的作用一样,后面的命令会以删除后的文件内容为准
sed '/ab/d' bfile
sed '/ab/d;=' bfile

# /i 在上一行插入
sed '/ab/i hello' bfile

# /a 在下一行插入
sed '/ab/a hello' bfile

# /c 替换行
sed '/ab/c hello' bfile

# /r 合并两个文件
sed '/ab/r cfile' bfile

# 打印行号 =
sed "=" bfile

# /n 操作匹配的下一行

# 打印匹配行,这个替换中的p不同,通常和-n参数配合只打印匹配到的行
sed -n '/ab/p' bfile

# 退出命令
sed 10q filename # 不会把文件全部读入
sed -n 1,10p filename

sed 多行模式

  • N:将下一行加入到模式空间中
  • D:删除模式空间中的第一个字符到第一个换行符
  • P:打印模式空间中第一个字符到第一个换行符
root@4ebe31ff7a18:/tmp# cat dfile
hel
lo
root@4ebe31ff7a18:/tmp# sed 'N;s/hel\nlo/!!!/' dfile
!!!
root@4ebe31ff7a18:/tmp# sed 'N;s/hel.lo/!!!/' dfile
!!!

# 多行操作
root@4ebe31ff7a18:/tmp# cat b.txt
hell
o bash hel
lo bash
# 两行连起来操作
root@4ebe31ff7a18:/tmp# sed 'N;s/\n//;s/hello bash/hello sed\n/;P;D' b.txt
hello sed
 hello sed
# 三行连起来操作
sed 'N;N;s/\n//;s/hello bash/hello sed\n/;P;D' b.txt

AWK

认识 awk

  • awk 更像是脚本语言
  • awk 用于比较规范的文本处理,用于统计数量并输出指定字段
  • sed 将不规范的文本,处理为比较规范的文本

AWK 的字段

  • 每行称作 AWK 的记录
  • 使用空格、制表符分隔开的单词成为字段
  • 可以自己制定分隔的字段
# -F 指定分隔符
# x++:打印行号
# ^menu:匹配行
awk -F "''" '/^menu/{ print x++, $2 }' /boot/grub2/grub.cfg

AWK 表达式

  • 系统变量

    • FS 表示输入的内容用什么分隔,OFS 表示输出用什么符号分隔
    • RS 行分隔符
    • NR 打印行号,如果文件变化了 NR 是不会重新排号,FNR 则会重新排号
    • NF 字段的数量
# 下面两行意义相同,BEGIN表示在输入内容之前的操作
head -n 6 /etc/passwd | awk 'BEGIN{FS=":"}{print $1}'
head -n 6 /etc/passwd | awk -F ':' '{print $1}	'

# 设置输出分隔符
head -n 6 /etc/passwd | awk 'BEGIN{FS=":";OFS="-"}{print $1,$2}

# 改变内容行的分隔符,改为通过:来换行,$0是输出一行
head -n 6 /etc/passwd | awk 'BEGIN{RS=":"}{print $0}'

# 打印行号
root@709230c0b366:~# awk '{print NR, $0}' /etc/hosts /etc/hosts
1 127.0.0.1    localhost
2 ::1    localhost ip6-localhost ip6-loopback
3 fe00::0    ip6-localnet
4 ff00::0    ip6-mcastprefix
5 ff02::1    ip6-allnodes
6 ff02::2    ip6-allrouters
7 172.17.0.4    709230c0b366
8 127.0.0.1    localhost
9 ::1    localhost ip6-localhost ip6-loopback
10 fe00::0    ip6-localnet
11 ff00::0    ip6-mcastprefix
12 ff02::1    ip6-allnodes
13 ff02::2    ip6-allrouters
14 172.17.0.4    709230c0b366
root@709230c0b366:~# awk '{print FNR, $0}' /etc/hosts /etc/hosts
1 127.0.0.1    localhost
2 ::1    localhost ip6-localhost ip6-loopback
3 fe00::0    ip6-localnet
4 ff00::0    ip6-mcastprefix
5 ff02::1    ip6-allnodes
6 ff02::2    ip6-allrouters
7 172.17.0.4    709230c0b366
1 127.0.0.1    localhost
2 ::1    localhost ip6-localhost ip6-loopback
3 fe00::0    ip6-localnet
4 ff00::0    ip6-mcastprefix
5 ff02::1    ip6-allnodes
6 ff02::2    ip6-allrouters
7 172.17.0.4    709230c0b366

# 打印有多少个字段
head -n 6 /etc/passwd | awk 'BEGIN{FS=":"}{print NF}'

# 打印最后一个字段的值
head -n 6 /etc/passwd | awk 'BEGIN{FS=":"}{print $NF}'

AWK 的判断和循环

root@7dc8bb7d5702:/tmp# cat a.txt
user1 34 54 23 12
user2 94 34 73 22
user3 99 45 12 49
root@7dc8bb7d5702:/tmp# awk '{ if($2>80) {print $1,$2} }' a.txt
user2 94
user3 99
root@7dc8bb7d5702:/tmp# awk '{ for(c=2;c<=NF;c++) print $c }' a.txt
34
54
23
12
94
34
73
22
99
45
12
49
root@7dc8bb7d5702:/tmp# awk '{ for(c=2;c<=NF;c++) sum+=$c; print sum}' a.txt
123
346
551

AWK 数组

# END表示数据读入完毕
root@7dc8bb7d5702:/tmp# awk '{ sum=0; for(c=2;c<=NF;c++) sum+=$c; average[$1]=sum/(NF-1) }END{ for( user in average ) print user,average[user] }' a.txt
user1 30.75
user2 55.75
user3 51.25
root@7dc8bb7d5702:/tmp# cat a.txt
user1 34 54 23 12
user2 94 34 73 22
user3 99 45 12 49
root@7dc8bb7d5702:/tmp# awk '{ sum=0; for(c=2;c<=NF;c++) sum+=$c; average[$1]=sum/(NF-1) }END{ for( user in average ) print user,average[user] }' a.txt
user1 30.75
user2 55.75
user3 51.25
root@7dc8bb7d5702:/tmp# awk '{ sum=0; for(c=2;c<=NF;c++) sum+=$c; average[$1]=sum/(NF-1) }END{ for( user in average ) sum2+=average[user]; print sum2/NR }' a.txt
45.9167

AWK 数组的应用

root@7dc8bb7d5702:/tmp# cat a.txt
user1 34 54 23 12
user2 94 34 73 22
user3 99 45 12 49
root@7dc8bb7d5702:/tmp# cat result.awk
{
sum = 0
for(c = 2; c <= NF; c++)
    sum += $c

average[$1] = sum / (NF - 1)
print $1, average[$1]

}
END{
for(user in average)
    sum_all += average[user]

avg_all = sum_all / NR

for(user in average)
    if (average[user] > avg_all)
        above++
    else
        below++

print "above", above
print "below", below

}
root@7dc8bb7d5702:/tmp# awk -f result.awk a.txt
user1 30.75
user2 55.75
user3 51.25
above 2
below 1

AWK 函数

# 整数
root@7dc8bb7d5702:/tmp# awk 'BEGIN{pi=3.114; print int(pi)}'
3

# 随机数
root@7dc8bb7d5702:/tmp# awk 'BEGIN{srand(); print rand()}'
0.739691
root@7dc8bb7d5702:/tmp# awk 'BEGIN{srand(); print rand()}'
0.00276686
root@7dc8bb7d5702:/tmp# awk 'BEGIN{srand(); print rand()}'
0.134305

# 自定义函数
root@7dc8bb7d5702:/tmp# awk 'function double(str) {return str str} BEGIN{print double("hello")}'
hellohello

Published under  on .

pipihua

我是皮皮花,一个前后端通吃的前端攻城狮,如果感觉不错欢迎点击小心心♥(ˆ◡ˆԅ) star on GitHub!