Linux Shell 脚本编程基础知识篇—awk编程语言(2)

发布于:2025-02-11 ⋅ 阅读:(49) ⋅ 点赞:(0)

ℹ️大家好,我是练小杰,今天是2025年第一天,元旦快乐各位😆
本文是有关Linux shell脚本编程的awk命令详解,后续我会不断增加相关内容 ~~
回忆:【awk编程语言(1)
更多Linux 相关内容请点击👉【Linux专栏】~

在这里插入图片描述

在这里插入图片描述

awk内置字符串函数

在这里插入图片描述

length(x) 返回x的长度

  • 打印文件lxj.txt中,若长度为x>=2时,输出动作
awk '{x=$1;y=$2;if(length(x)>=2) print "$1 is:" x}' lxj.txt 
$1 is:It
$1 is:It

gsub( )函数

  • gsub()函数的返回值是替换的个数!
  • gsub( ) 只对内存中的内容起作用,并不修改文件本身!
  • gsub(r,s) 在整个$0中用s替代r
  • gsub(r,s,t) 在整个t中用s替代r
[root@localhost ~]# cat Ftest.txt
127.0.0.1; ?   localhost? localhost.localdomain localhost4 ;localhost4.localdomain4
::1;space?     localhost? localhost.localdomain localhost6; localhost6.localdomain6

[root@localhost ~]# awk '{print gsub("local","127")}'   Ftest.txt
  6
  6

可以看到,说明在上述例子中,127 替换了6个local!

  • 利用gsub( )函数把 bed替换good文件内容
[root@localhost ~]# echo "you are bed boy">lxj.txt 
[root@localhost ~]# awk '{gsub("bed","good")} {print}'  lxj.txt
you are good boy

index 函数

index(s1, s2) 函数用于查找字符串 s2 在字符串 s1 中第一次出现的位置。
如果找到,返回 s2 在 s1 中第一次出现的位置(从 1 开始计数);如果未找到,则返回 0。

  • 基本语法:
index(s1, s2)

s1: 要搜索的主字符串
s2: 要查找的目标字符串

基本用法

  • 假设有文本文件 example.txt,内容为

Hello, world!
awk is a good tool.
Hello again!

  1. 使用 index 函数查找 “world” 在每一行中的位置
awk '{print index($0, "world")}' example.txt

输出结果:

8
0
0

可以看到,第一行 “Hello, world!” 中,“world” 从第 8 个字符开始。
第二行和第三行中不包含 “world”,因此返回 0。

  1. 查找子字符串的位置
echo "The quick brown over the lazy dog" | awk '{print index($0, "brown")}'

输出结果:

11

可以看到,“brown” 在字符串中的位置是第 11 个字符

实际用法

  • 假设有一个包含多个 URL 的文件 urls.txt

https://blog.csdn.net/weixin_55767624
https://www.example.com
ftp://fileserver.com
https://secure.example.com/login

  • 要查找包含 “example” 的 URL,可以使用 index 函数:
awk 'index($0, "example") > 0' urls.txt

输出:

https://www.example.com
https://secure.example.com/login

说明: index($0, "example") > 0 表示当 “example” 在行中出现的位置大于 0 时,即该行包含 “example”

match 函数

  • match(s, r) 函数用于在字符串 s 中查找正则表达式 r 的匹配。如果找到,返回匹配字符串的起始位置(从 1 开始计数);如果未找到,则返回 0。
  • match 函数还会设置两个内置变量:RSTARTRLENGTH,分别表示匹配字符串的起始位置和长度

语法格式:

match(s, r)

s: 要搜索的主字符串
r: 要匹配的正则表达式

基本用法

  • 假设有以下文本文件 example.txt

Hello, lxj!
awk is a powerful tool.
Hello again!

  • 使用 match 函数查找 “lxj” 在每一行中的位置:
awk '{pos = match($0, /lxj/); print pos}' example.txt

输出结果:

8
0
0

第一行 “Hello, lxj!” 中,“lxj” 从第 8 个字符开始
第二行和第三行中不包含 “world”,因此返回 0

使用 RSTART 和 RLENGTH

  • match 函数设置了 RSTART 和 RLENGTH 两个内置变量

  • RSTART: 匹配字符串的起始位置

  • RLENGTH: 匹配字符串的长度

echo "The quick brown fox jumps over the lazy dog" | awk '{
    match($0, /brown/);
    print "Position: " RSTART ", Length: " RLENGTH
}'

输出结果:

Position: 11, Length: 5

由此可知,“brown” 在字符串中的位置是第 11 个字符,长度为 5。

match 函数的实际应用

  1. 查找并处理匹配的部分
  • 假设有一个包含电子邮件地址的文件 emails.txt
Alice <alice@example.com>
Bob bob@test.com
Charlie: charlie@domain.org
  • 要查找所有电子邮件地址并提取用户名和域名
awk '{
    if (match($0, /<([^>]+)>|[^[:space:]:]+@[^[:space:]:]+/)) {
        email = substr($0, RSTART, RLENGTH);
        if (email ~ /<([^>]+)>/) {
            username = substr(email, 2, length(email) - 2);
        } else {
            username = email;
        }
        split(email, parts, "@");
        domain = parts[2];
        print "Username: " username ", Domain: " domain
    }
}' emails.txt
  • 输出结果
Username: alice, Domain: example.com
Username: bob, Domain: test.com
Username: charlie, Domain: domain.org

说明:
1.match 函数查找符合电子邮件地址模式的字符串。
2.使用 substr 提取电子邮件地址。
3.使用正则表达式判断是否包含 < 和 >,并提取用户名。
4.使用 split 函数分割电子邮件地址,提取域名。
5.打印用户名和域名。

  1. 查找并替换匹配的部分
  • 有一个包含日期的文件 dates.txt

Today is 2023-10-05.
The event is scheduled for 2023/11/25.
Last updated on 2023.12.31.

  • 要将日期格式统一为 YYYY-MM-DD
awk '{
     while (match($0, /[0-9]{4}[-/][0-9]{2}[-/][0-9]{2}/)) {
        date = substr($0, RSTART, RLENGTH);
        gsub(/-/, "/", date);
        sub(/[0-9]{4}[-/][0-9]{2}[-/][0-9]{2}/, date, $0);
    }
    print
}' dates.txt
  • 输出结果:
Today is 2023-10-05.
The event is scheduled for 2023/11/25.
Last updated on 2023/12/31.

说明:

  1. match 函数查找符合日期格式的字符串。
  2. 使用 substr 提取日期。
  3. 使用 gsub- 替换为 /
  4. 使用 sub 将原始日期替换为新的日期格式。
  5. 重复上述过程直到所有日期都被处理。
  6. 打印处理后的行。

awk内置变量

  • 变量提高了awk程序可读性
    在这里插入图片描述

行号:NG

ls -l | awk '{print NR,$0}' 

1 total 24
2 -rw-------. 1 root root 2767 Jun 10  2020 anaconda-ks.cfg
3 drwxr-xr-x. 2 root root    6 May  7  2021 Desktop
4 drwxr-xr-x. 2 root root    6 Jun 10  2020 Documents
5 drwxr-xr-x. 2 root root    6 Jun 10  2020 Downloads
6 drwxr-xr-x. 2 root root    6 Jun 10  2020 Music
7 -rwxr--r--. 1 root root   28 Mar 30  2021 net.sh
8 -rw-------. 1 root root 2047 Jun 10  2020 original-ks.cfg
9 drwxr-xr-x. 2 root root    6 Jun 10  2020 Pictures
10 -rw-r--r--. 1 root root  298 Apr 12 01:37 printf.sh
11 drwxr-xr-x. 2 root root    6 Jun 10  2020 Public
12 drwxr-xr-x. 2 root root    6 Jun 10  2020 Templates
13 -rw-r--r--. 1 root root  467 Apr 12 08:16 test1.txt
14 -rw-r--r--. 1 root root  167 Apr 12 08:00 test.txt
15 drwxr-xr-x. 2 root root    6 Jun 10  2020 Videos

NF:域个数

  • 利用NF变量输出域个数
[root@localhost ~]# ls -l | awk '{print NF,$0}' 
2 total 24
9 -rw-------. 1 root root 2767 Jun 10  2020 anaconda-ks.cfg
9 drwxr-xr-x. 2 root root    6 May  7  2021 Desktop
9 drwxr-xr-x. 2 root root    6 Jun 10  2020 Documents
9 drwxr-xr-x. 2 root root    6 Jun 10  2020 Downloads
9 drwxr-xr-x. 2 root root    6 Jun 10  2020 Music
[root@localhost ~]# awk '{print NF}' /etc/hosts
5
5
[root@localhost ~]# awk '{print NF,$5}' /etc/hosts
5 localhost4.localdomain4
5 localhost6.localdomain6
[root@localhost ~]# awk '{print $NF}' /etc/hosts
localhost4.localdomain4
localhost6.localdomain6

NR与FNR

  • NR将所有文件的数据视为一个数据流。
  • FNR则是将多个文件的数据视为独立的若干个数据流,遇到新文件时行号从1开始重新递增。
[root@localhost ~]# awk '{print NR "\t"$1}' /etc/hosts test.txt
1	127.0.0.1
2	::1
1	127.0.0.1
2	::1;
[root@localhost ~]# awk '{print FNR, "\t",$1}' /etc/hosts test.txt
1 	 127.0.0.1
2 	 ::1
1 	 127.0.0.1
2 	 ::1;

自定义变量

[root@localhost ~]# awk -v x="hello" -v y="OK" '{print x,y}' /etc/hosts
hello OK
hello OK


[root@localhost ~]# awk -v shell=$SHELL '{print shell}' /etc/hosts    #调用系统变量
/bin/bash
/bin/bash
[root@localhost ~]# awk '{print "'$SHELL'"}' /etc/hosts
/bin/bash
/bin/bash

内置变量RS、OFS、ORS区别

  • RS变量
    内置变量RS保存的是输入数据的行分隔符,默认为\n,可以指定其它字符作为行分隔符
awk -v RS="." '{print $1}' /etc/hosts

127
0
0
1
localdomain
localdomain4
localdomain
localdomain6
  • OFS变量
    保存的是输出字段的分隔符(列分隔符),默认为空格
awk -v  OFS="," '{print $1,$2,$3}' /etc/hosts

127.0.0.1,localhost,localhost.localdomain
::1,localhost,localhost.localdomain
  • ORS变量
    保存的是输出记录的分隔符
awk -v ORS="@" '{print $1,$2,$3}' /etc/hosts

127.0.0.1 localhost 
localhost.localdomain@::1 localhost 
localhost.localdomain@ 

今天awk的内容就到这里,蛇年来啦😆
如果想了解更多,点击主页【练小杰的CSDN
⚠️若博客里的内容有问题,欢迎指正,我会及时修改!!!
明天再见,各位🧍‍♂️大佬们~~


网站公告

今日签到

点亮在社区的每一天
去签到