【Linux入门】Shell 函数、正则表达式与文本处理:cut 与 awk

文章目录

  • 一、函数
    • [1. 系统函数:basename](#1. 系统函数:basename)
    • [2. 系统函数:dirname](#2. 系统函数:dirname)
    • [3. 自定义函数](#3. 自定义函数)
  • 二、正则表达式入门
    • [1. 常规匹配](#1. 常规匹配)
    • [2. 特殊字符 `^`:匹配一行的开头](#2. 特殊字符 ^:匹配一行的开头)
    • [3. 特殊字符 `\`:匹配一行的结束](#3. 特殊字符 ``:匹配一行的结束)
    • [4. 特殊字符 `.`:匹配一个任意字符](#4. 特殊字符 .:匹配一个任意字符)
    • [5. 特殊字符 `*`:匹配前一个字符 0 次或多次](#5. 特殊字符 *:匹配前一个字符 0 次或多次)
    • [6. 字符区间(中括号)` `:匹配某个范围内的一个字符](#6. 字符区间(中括号)[ ]:匹配某个范围内的一个字符)
    • [7. 特殊字符 `\`:转义](#7. 特殊字符 \:转义)
  • 三、文本处理工具:cut
  • 四、文本处理工具:awk
  • 五、总结

一、函数

1. 系统函数:basename

基本语法:

shell 复制代码
basename [string / pathname] [suffix]

功能描述: basename 命令会删掉所有的前缀包括最后一个 / 字符,然后将字符串显示出来。可以理解为取路径里的文件名称 。其中 suffix 为后缀,如果指定了 suffix,basename 会将 pathname 或 string 中的 suffix 去掉。

案例实操: 截取 /home/xiaoxiaoguai/test.txt 路径的文件名称。

shell 复制代码
basename /home/xiaoxiaoguai/test.txt
# test.txt

basename /home/xiaoxiaoguai/test.txt .txt
# test

2. 系统函数:dirname

基本语法:

shell 复制代码
dirname 文件绝对路径

功能描述: 从给定的包含绝对路径的文件名中,去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)。可以理解为取文件所在目录的路径

案例实操: 获取 test.txt 文件的路径。

shell 复制代码
dirname /home/xiaoxiaoguai/test.txt
# /home/xiaoxiaoguai

3. 自定义函数

基本语法:

shell 复制代码
[ function ] funname[()]
{
  Action;
  [return int;]
}

经验技巧:

  1. 必须在调用函数地方之前先声明函数------Shell 脚本是逐行运行的,不会像其他语言一样先编译。
  2. 函数返回值只能通过 $? 系统变量获得。可以显式加 return 返回;如果不加,将以最后一条命令的运行结果作为返回值。return 后跟数值 n(0-255)。

案例实操: 计算两个输入参数的和。

shell 复制代码
touch func.sh
vim func.sh
shell 复制代码
#!/bin/bash
function sum()
{
  s=0
  s=$[ $1+$2 ]
  echo "$s"
}
read -p "Please input the number1: " n1;
read -p "Please input the number2: " n2;
sum $n1 $n2

执行:

shell 复制代码
chmod 777 func.sh
[root@node1 ~]# ./func.sh
Please input the number1: 3
Please input the number2: 3
6

补充 :在函数内部可以使用 local 声明局部变量,变量作用域仅限于该函数,避免污染全局环境:

shell 复制代码
function test() {
  local x=10
  echo $x
}

二、正则表达式入门

正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。

在 Linux 中,grep、sed、awk 等文本处理工具都支持通过正则表达式进行模式匹配。

1. 常规匹配

一串不包含特殊字符的正则表达式匹配它自己:

shell 复制代码
cat /etc/passwd | grep xiaoxiaoguai
# 匹配出所有包含 xiaoxiaoguai的行

2. 特殊字符 ^:匹配一行的开头

shell 复制代码
cat /etc/passwd | grep ^a
# 匹配出所有以 a 开头的行

3. 特殊字符 $:匹配一行的结束

shell 复制代码
cat /etc/passwd | grep t$
# 匹配出所有以 t 结尾的行

4. 特殊字符 .:匹配一个任意字符

shell 复制代码
cat /etc/passwd | grep r..t
# 匹配出包含 r 开头、t 结尾(中间任意两个字符)的所有行

5. 特殊字符 *:匹配前一个字符 0 次或多次

shell 复制代码
# * 不单独使用,它和上一个字符连用,表示匹配上一个字符 0 次或多次
cat /etc/passwd | grep ro*t
# 匹配 rt、rot、root、rooot、roooot 等所有行

6. 字符区间(中括号)[ ]:匹配某个范围内的一个字符

shell 复制代码
[68]        # 匹配 6 或者 8
[0-9]       # 匹配一个 0-9 的数字
[0-9]*      # 匹配任意长度的数字字符串
[a-z]       # 匹配一个 a-z 之间的字符
[a-z]*      # 匹配任意长度的字母字符串
[a-ce-f]    # 匹配 a-c 或者 e-f 之间的任意字符

案例实操:

shell 复制代码
cat /etc/passwd | grep r[abc]*t
# 匹配 rt、rat、rbt、rabt、rbact、rabccbaaacbt 等等所有行

注意:[6,8] 这种写法会把逗号也当作可匹配字符,表示 6、,、8 三者之一;想要匹配 6 或 8 应写作 [68]。同理,区间合并应写成 [a-ce-f]

7. 特殊字符 \:转义

\ 表示转义,不会单独使用。由于所有特殊字符都有其特定匹配模式,当想匹配某一特殊字符本身时(例如找出所有包含 $ 的行),就要将转义字符和特殊字符连用,来表示特殊字符本身:

shell 复制代码
cat /etc/passwd | grep 'a\$b'
# 匹配所有包含 a$b 的行,注意需要使用单引号将表达式引起来

三、文本处理工具:cut

cut 的工作就是"剪"------在文件中负责剪切数据,从每一行剪切字节、字符和字段并输出。

基本语法:

shell 复制代码
cut [选项参数] filename
# 说明:默认分隔符是制表符(Tab)

常用选项:-d 指定分隔符,-f 指定要取的列。

案例实操:

shell 复制代码
# 数据准备
touch cut.txt
vim cut.txt
# 添加以下内容
zhang san
li si
wang wu
shu jia
lan zhi
shell 复制代码
# 1、切割 cut.txt 第一列(-d 指定分隔符为空格,-f 指定列号)
cut -d " " -f 1 cut.txt
# zhang
# li
# wang
# shu
# lan

# 2、切割 cut.txt 第二、三列
cut -d " " -f 2,3 cut.txt

# 3、在 cut.txt 中先过滤出含 shu 的行,再切割出第一列
cat cut.txt | grep shu | cut -d " " -f 1
# shu

# 4、选取系统 PATH 变量值中,第 2 个 ":" 开始后的所有路径
echo $PATH | cut -d ":" -f 3-

# 5、切割 ifconfig 输出中的 IP 地址
ifconfig ens33 | grep netmask | cut -d " " -f 10

提示:ifconfig 输出的缩进格式会因系统/版本而异,用 cut 取固定列号不够通用,更稳妥的做法是使用 awk 按字段精确提取(见下文):

shell 复制代码
ifconfig ens33 | awk '/netmask/ {print $2}'

另外,网卡名称(如 ens33)在不同机器上可能不同,请以实际环境为准。

四、文本处理工具:awk

awk 是一个强大的文本分析工具 :把文件逐行读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。

基本语法:

shell 复制代码
awk [选项参数] '/pattern1/{action1} /pattern2/{action2}...' filename
  • pattern:表示 awk 在数据中查找的内容,即匹配模式;
  • action:在找到匹配内容时所执行的一系列命令。

案例实操:

shell 复制代码
# 数据准备
cp /etc/passwd ./

/etc/passwd 每行各字段含义:用户名:密码(加密后):用户id:组id:注释:用户家目录:shell解析器

shell 复制代码
# 1、搜索 passwd 文件中以 root 开头的所有行,并输出该行的第 7 列
#    -F : 表示以冒号为分隔符
awk -F : '/^root/{print $7}' passwd
# /bin/bash

# 2、搜索以 root 开头的行,输出第 1 列和第 7 列,中间以 "," 分割
awk -F : '/^root/{print $1","$7}' passwd
# root,/bin/bash
# 注意:只有匹配了 pattern 的行才会执行 action

# 3、显示 passwd 的第一列和第七列,以逗号分割,
#    所有行前面添加列名 user,shell,最后一行添加 "lanzhishujia,/bin/bigdata"
awk -F : 'BEGIN{print "user, shell"} {print $1","$7} END{print "lanzhishujia,/bin/bigdata"}' passwd
# 注意:BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行

# 4、将 passwd 文件中的用户 id 增加数值 1 并输出(-v 用于传外部变量给 awk)
awk -v i=1 -F : '{print $3+i}' passwd

awk 的内置变量:

内置变量 含义
FILENAME 当前输入文件的文件名
NR 已读出的记录数(行号)
NF 当前记录(行)的字段个数
$NF 当前行的最后一列(补充)

案例实操:

shell 复制代码
# 1、统计 passwd 文件名、每行的行号、每行的列数
awk -F : '{print "filename:" FILENAME ",linenum:" NR ",col:"NF}' passwd

# 2、查询 ifconfig 命令输出结果中空行所在的行号
ifconfig | awk '/^$/{print NR}'

# 3、切割 IP(awk 方式,比 cut 取固定列更稳定)
ifconfig ens33 | awk '/netmask/ {print $2}'

五、总结

知识点 关键内容
系统函数 basename 取文件名、dirname 取目录路径
自定义函数 [ function ] funname() { ... [return n;] },先声明后调用
正则元字符 ^ $ . * [ ] \
cut -d 指定分隔符、-f 指定列,默认分隔符为制表符
awk -F 分隔符、pattern/action、BEGIN/END-v 传变量
awk 内置变量 FILENAMENRNF$NF
相关推荐
Zenova EdgeOS1 小时前
Linux dmesg 工业边缘实战:内核日志过滤、持久化与故障定位
linux·运维·边缘计算·工业边缘·dmesg·内核日志
金士顿1 小时前
System.Text.Json Source Generator 深度解析:为什么 Native AOT 不喜欢反射
linux·asp.net core·arm64·net·native aot
wdfk_prog2 小时前
ROS教程08:从 TransportTCP::connect() 追到 TCPROS Connection Header、序列化与 Socket 数据传输
运维·缓存·docker·容器·ros
做运维的阿瑞2 小时前
Python 标准库汇总:分类速览与常用模块清单
linux·运维·python
百万蹄蹄向前冲3 小时前
密码都对Node.js却连不上Linux数据库
linux·mysql
彧azz3 小时前
Linux 网络编程学习总结
linux·网络·笔记·学习·面试
日常筹谋记3 小时前
自动化仓储安全防护工况评估:明治传感器AS-33C技术适配性分析
大数据·运维·创业创新·业界资讯
susplus4 小时前
【ARM 裸机开发 (IMX6ULL-mini)】GNU工具、Makefile 工程构建、链接脚本详解|C 语言点灯 + 蜂鸣器驱动
linux·arm·makefile·imx6ull
Shadow(⊙o⊙)4 小时前
Linux进阶知识1.0
linux·运维·服务器