linux 正则表达式+文本三剑客

2024-05-15 19:52

本文主要是介绍linux 正则表达式+文本三剑客,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、正则表达式

1.正则表达式的概念

REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符。

正则表达式被很多程序和开发语言所广泛支持:vim, less,grep,sed,awk, nginx,mysql 等

1.1正则表达式与通配符的区别

正则表达式主要用来匹配字符串(命令结果,文本内容)

通配符匹配文件(而且是已存在的文件)

  • 基本正则表达式

  • 扩展正则表达式

1.2 元字符(字符匹配)

.   匹配任意单个字符,可以是一个汉字  
[]   匹配指定范围内的任意单个字符,示例:[zhou]   [0-9]   []   [a-zA-Z]   [[:alpha:]]    [0-9a-zA-Z]= [:alnum:]
[^] 匹配指定范围外的任意单个字符,示例:[^zhou] [^a.z] [a.z]
[:alnum:] 字母和数字`
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母`
[:blank:] 空白字符(空格和制表符)
[:space:] 包括空格、制表符 (水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包含的范围广
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
\w #匹配单词构成部分,等价于[_[:alnum:]]
\W #匹配非单词构成部分,等价于[^_[:alnum:]]
\S     #匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。

 \s #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意Unicode 正则表达式会匹配全角空格符`

1.3表示次数
*#匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* #任意长度的任意字符  不包括0次     
\? #匹配其前面的字符出现0次或1次,即:可有可无
\+ #匹配其前面的字符出现最少1次,即:肯定有且 >=1 次
\{n\} #匹配前面的字符n次
\{m,n\} #匹配前面的字符至少m次,至多n次
\{,n\}  #匹配前面的字符至多n次,<=n
\{n,\}  #匹配前面的字符至少n次
ifconfig ens33|grep netmask|grep -o 
​
#举例
过滤ip地址
[root@xkj ~]# ifconfig ens33|grep netmask|grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'|head -n1
192.168.100.254
​

1.4 位置锚定

^ #行首锚定, 用于模式的最左侧
$ #行尾锚定,用于模式的最右侧
^PATTERN$ #用于模式匹配整行 (单独一行  只有root)
^$ #空行   
^[[:space:]]*$ #  空白行    tab   换行  回车
​
​
\< 或 \b        #词首锚定,用于单词模式的左侧(连续的数字,字母,下划线都算单词内部)
\> 或 \b        #词尾锚定,用于单词模式的右侧
\<PATTERN\>     #匹配整个单词
思考过滤出不是已#号开头的非空行
[root@localhost ~]#grep "^[^#]" /etc/fstab
[root@localhost data]#grep "^google$" test.txt
#只匹配google 这个字符
​
[root@localhost ~]#grep "^[[:space:]]*$" /etc/fstab
​
[root@localhost ~]#echo hello-123 |grep "\<123"
#除了 字母 数字 下划线其他都算 单词的分隔符
hello-123
[root@localhost ~]#echo hello 123 |grep "\<123"
hello 123
​

1.5 分组或其他

分组:( ) 将多个字符捆绑在一起,当作一个整体处理,如:(root)+

后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名

方式为: \1, \2, \3, ... 分组

\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符

示例

[root@localhost ~]#echo abccc |grep "abc\{3\}"
abccc
​
[root@localhost ~]#echo abcabcabc |grep "\(abc\)\{3\}"
#分组 匹配abc
abcabcabc
[root@localhost ~]#echo 1abc |grep  "1\|2abc"
#只匹配了1
1abc
​
[root@localhost ~]#echo 1abc |grep  "\(1\|2\)abc"
#1abc或者2abc
1abc
​
[root@localhost ~]#ifconfig ens33|grep netmask|grep -o '\([0-9]\{1,3\}\.\)\{3\}[0-9]\{3\}'|head -1
192.168.91.100
​
[root@localhost ~] ens33 |grep netmask|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'|head -1
​
[root@localhost ky15]#ifconfig ens33 |grep netmask|grep -Eo '([0-9]{1,3}.){4}'

1.6 扩展正则表达式(表示字符相差不大)

grep -E

egrep 默认使用的 是扩张正则

表示次数

*   匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次
{,n}  #匹配前面的字符至多n次,<=n,n可以为0
{n,} #匹配前面的字符至少n次,<=n,n可以为0

表示分组

() 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:\1, \2, ...
| 或者  
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat
​

二、文本命令

1.grep命令

1.1基本格式

grep [选项]… 查找条件 目标文件

1.2常用选项
选项功能
-m[x]匹配x次后停止,x为具体数字
-v取反
-i忽略字符大小写
-n显示匹配的行号
-c统计匹配的行数
-o仅显示匹配到的字符串
-q静默模式,不输出任何信息
-e实现多个选项间的逻辑or关系
-w匹配整个单词
-E使用扩展正则表达式,相当于egrep
-F不支持正则表达式,相当于fgrep
-r递归目录,但不处理软连接
-R递归目录,但处理软连接
-f处理两个文件相同内容,把第一个文件作为匹配条件
-A x匹配内容的后x行
-B x前x行
-C x前后各x行
[root@xkj ~]# grep -m 1 root /etc/passwd #只匹配一次
root:x:0:0:root:/root:/bin/bash
[root@xkj ~]# grep -m 5 root /etc/passwd #匹配多次
匹配多次root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
​
[root@xkj ~]# grep -Ev '^[[:space:]]*#|^$' /etc/fstab
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=6a6b9aa4-d7dd-4a07-a45e-a59fd506806d /boot                   xfs     defaults        0 0
/dev/mapper/centos-home /home                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
#使用拓展正则表达式匹配不以空格和#开头的行
​
[root@xkj ~]# grep -A3 root /etc/passwd #匹配含root的行和后三行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
--
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
​
[root@xkj ~]# grep -e root -e bash  /etc/passwd
#匹配包含root或者bash的行 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
xkj:x:1000:1000:xkj:/home/xkj:/bin/bash
​
[root@xkj ~]# grep -c root  /etc/passwd  #统计包含root的行数
2
​
​
​

2.sed命令

1.1sed核心功能
sed的核心功能:增删改查(可配合正则表达式)
查: p
​
删: d
​
改: s(字符串替换)、c(整行替换)、y(对应字符进行替换,效果类似tr命令)
​
增: i(在行前插入内容)、a(在行后添加内容)、r(在行后读入文件的内容)
​
复制粘贴:H(复制)、d(删除)、G(粘贴到指定行下方)
​
1.2 命令格式
sed [option]... 'script;script;...' [input  file...]选项         自身脚本语法         支持标准输入管道
1.3常用选项
选项功能
-n不输出模式空间内容到屏幕(不自动打印)
-e类似grep的-e,可实现多脚本运行
-f从指定文件中读取编辑脚本
-r或者-E使用拓展正则表达式
-i.bak备份文件并原处编辑
-s将多个文件视为独立文件,而不是单个连续的长文件流
[root@xkj ~]# sed -n -e '/^r/p'  -e'/^b/p' /etc/passwd 
#把passwd文件中r为首和b为首的内容打印出来
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
​
​
​
1.4 sed脚本语法
1.4.1 基本语法结构
[address]<command>[options]匹配范围   命令      选项
​
address  表示要匹配的行范围,可以是单个行号、行号范围或正则表达式。
command  表示要在匹配的行上执行的命令。
options  是一些可选的参数,用于修改命令的行为。
1.4.2 地址部分(指定匹配范围)

在 sed 脚本中,地址部分用于指定要匹配的行范围。 地址部分可以是单个行号、行号范围或正则表达式。

1)不指定范围

地址部分是可选的,如果不指定地址,Sed 将对所有行都执行命令

2)单个行号
#基本格式#
sed  'n<command>' file #处理第n行的内容,n为具体正整数
#举个例子#
sed '2d' file #删除文件中的第 2 行。
​
​
3)行号范围
#基本格式#
sed 'x,y<command>' file  #处理x行到y行的内容,x和y为正整数且x<y
​
sed 'x,+y<command>' file #处理x行和x行后y行的内容
​
#举个例子#
sed '2,5d' file  #删除文件中第2行到第5行的内容
​
sed '2,+5d' file #删除文件中第2行到第7行的内容
​
​
4)使用正则表达式匹配范围
#基本格式#
sed '/pattern/<command>' file #根据正则表达式来匹配目标行
​
sed '/pattern1/,/pattern2/<command>' file 
#匹配正则表达式1和正则表达式2间的行,并根据command进行处理
​
sed 'x,/pattern/<command>' file  #x行到正则表达式匹配到的行之间的内容
sed '/pattern/,y<command>' file  #正则表达式匹配到的行到y行之间的内容
​
[root@xkj ~]# sed -n  '/^root/,/^daemon/p' /etc/passwd
#打印出root开头到daemon开头的行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
​

5)步进
'~' 符号
​
#怎么表示奇数行?
sed  -n '1~2p' #从第一行开始,步进为2打印,即1 3 5 7。。。
sed '0~2d'
​
#怎么表示偶数行?
sed  -n '2~2p' #从第二行开始,步进为2打印,即2 4 6 8。。。
sed '1~2d' 
6)最后一行和倒序匹配
`$` 符号用于表示最后一行
​
sed -n '$<command>' file #对最后一行进行操作
​
sed -n '$,$-n<command>' file #倒数第n行到最后一行
​
1.4.3命令部分(要执行的命令)
命令功能
p将匹配到的行打印输出
lp忽略大小写输出
d删除模式空间匹配的行,并立即启用下一轮循环
a\将指定的文本添加到匹配到的行后面
i\将指定的文本插入到匹配到的行前面
c\替换行为单行或多行文本
w 文件保存模式匹配的行至指定文件
r 文件读取指定文件的文本至模式空间中匹配到的行后
=为模式空间中的行打印行号
模式空间中匹配行取反处理
q结束或退出sed
#用sed打印到第三行
​
sed -n '1,3p' 文件
​
sed '3q'  文件 #q是自动退出,打印到第三行就退出
​
#打印从第三行开始,继续往后打印三行
​
sed -n '3,+3p'
特殊字符和转义序列
​
&: 表示与模式匹配的整个文本。
\1, \2, ...: 表示与模式中括号内的子表达式匹配的文本。
\n: 表示换行符。
\t: 表示制表符。
\\: 表示反斜杠。
​
1.5 sed查找替换
1.5.1 基本语法
sed 's/要查找的内容/替换的内容/修饰符' 文件名 
# '/'为分隔符,可以用'@' 或者 '#'
# 要查找的内容可以用正则表达式 
# 替换的内容无法用正则表达式
​
# 修饰符 #
g 行内全局替换
p 显示替换成功的行
w   /PATH/FILE 将替换成功的行保存至文件中
I,i   忽略大小写
​
sed -i 's/r..t/&er/g'  /etc/passwd
# &代指前面找到的内容
​
1.5.2 sed分组和后向引用
1.分组

通过将模式的一部分放入一个分组中,可以将这部分模式视为一个单元,后续可以通过引用该分组在替换中使用。

2.后向引用

在替换中使用前面定义的分组的内容。在sed命令中,可以使用 \数字的形式引用分组,其中数字表示分组的顺序。

在替换中使用\1来引用第一个分组的内容。如果有多个分组,可以使用\2、\3等来引用后续分组的内容。

#举个例子
​
echo 123abcxyz | sed -nr 's/(123)(abc)(xyz)/\1/p'
# -n 关闭自动打印 -r 使用扩展正则表达式
# 123分成1组  abc分组第二组  xyz分成第三组 
# \1/p 表示打印第一组
​
[root@xkj ~]# echo 123abcxyz | sed -nr 's/(123)(abc)(xyz)/\1/p'
123
​
示例1  仅显示本机ip地址
[root@xkj ~]# ifconfig ens33 | sed -nr 's/.*inet (.*)  netmask.*/\1/p'
192.168.100.254
​
示例2 仅显示tmp文件的权限
[root@xkj ~]# stat /tmp文件:"/tmp"大小:8192       块:24         IO 块:4096   目录
设备:fd00h/64768d Inode:67148168    硬链接:83
权限:(1777/drwxrwxrwt)  Uid:(    0/    root)   Gid:(    0/    root)
环境:system_u:object_r:tmp_t:s0
最近访问:2016-11-05 23:38:36.000000000 +0800
最近更改:2024-05-15 16:06:11.881576249 +0800
最近改动:2024-05-15 16:06:11.881576249 +0800
创建时间:-
​
[root@xkj /]# stat tmp | sed -nr  '4s/.*\(([0-9]+)\/.*/\1/p'
1777
​
1.5.3 变量调用
name=root #定义变量
sed -nr '/'$name'/p' /etc/passwd #打印出包含root的内容
或者
sed -nr /"$name"/p /etc/passwd
[root@xkj /]# name=root
[root@xkj /]# sed -nr '/'$name'/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
​
​

3.awk命令

3.1awk工作原理

读取输入:AWK首先读取输入文件或从标准输入接收输入;

分割输入:AWK默认将输入行分割成字段,并使用空格或制表符作为字段分隔符;

匹配模式:AWK使用模式匹配来确定需要处理的行,可以使用正则表达式或其他条件来指定匹配的行。如果没有指定模式,AWK将默认匹配所有行;

执行动作:当输入行与模式匹配时,AWK执行相应的动作;

处理下一行:一旦完成当前行的处理,AWK继续处理下一行,重复上述步骤。

3.2awk命令格式
#命令格式#
awk [选项] '[模式匹配条件]{处理动作 }'  文件1 文件2..
3.2.1常用选项
#选项#
​
#一般只有-F常用
-F  指定分隔符,默认的分隔符是若干个连续空白符,默认的时候可不写
-v  自定义变量
-f  脚本
​
​
awk '/匹配条件/{ print $x }'
​
#匹配条件可以不写 x为任意数字
​
3.2.2 模式匹配条件
#模式匹配条件格式#/    匹配条件       / 
# 起始               结束    
#/  / 一定要加 
​
3.2.3 处理动作
#操作#
#常用的 只有 print 
​
awk  '{ print $1  }'
​
awk '{ print $1 $2 $3 .... }'
​
#awk会自动压缩空格,不需要再写tr -s '  '
​
3.3awk常用内置变量
内置变量功能
FS指定每行文本的字段分隔符,缺省为空格或制表符(tab)。与 “-F”作用相同 -v “FS=:”
OFS在输出中字段之间的分隔符,默认为空格
ORS在输出中记录之间的分隔符,默认为换行符
NF字段数量,表示当前记录中的字段数
NR记录编号,表示当前正在处理的输入记录的行号
RS表示用于分割记录的字符,默认为换行符
$0当前处理的行的整行内容
$n当前处理行的第n个字段(第n列)
FILENAME当前正在处理的文件的名称
3.4 BEGIN和END
BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作;
​
awk再处理指定的文本,之后再执行END模式中指定的动作;
​
END{ } 语句块中,往往会放入打印结果等语句
​
awk 'BEGIN {x=0};/\/bin\/bash$/;{x++};END{print x}' /etc/passwd
​
{x=0}          # 在开始之前,初始化变量x为0
/\/bin\/bash$/ # 使用正则表达式匹配包含"/bin/bash"的行
{x++}          # 每匹配到一行,变量x加1
END {print x}  # 结束后,输出变量x的值
​
[root@xkj /]# awk 'BEGIN {x=0};/\/bin\/bash$/;{x++};END{print x}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
xkj:x:1000:1000:xkj:/home/xkj:/bin/bash
44
​
3.5 NR
示例1  打印特定行号行的内容
[root@xkj /]# awk 'NR==3' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
#打印第三行的内容
​
示例2  计算输入文件的总行数
[root@xkj /]# awk 'END {print NR}' /etc/passwd
44
​
示例3  奇偶数行
NR%2==1取奇数行
NR%2==0取偶数行
awk 'NR%2==1 {print $2}' 文件名 #奇数行提取
awk 'NR%2==0 {print $2}' 文件名 #偶数行提取
[root@xkj /]# awk 'NR%2==1 {print $1}' test.txt 
1
3
5
7
9
[root@xkj /]# awk 'NR%2==0 {print $1}' test.txt 
2
4
6
8
10
​
示例4 多行处理
[root@xkj /]# awk '{if (NR%2 == 0) {print "aaa: " $0} else {print "bbb: " $0}}' test.txt
bbb: 1
aaa: 2
bbb: 3
aaa: 4
bbb: 5
aaa: 6
bbb: 7
aaa: 8
bbb: 9
aaa: 10
​
​
3.6 NF
示例1  打印每一行的字段数量
[root@xkj /]# awk '{print NF}' test.txt
2
2
1
1
2
1
2
1
1
1
​
​
示例2 打印每一行的最后一个字段
[root@xkj /]# awk '{print $NF}' test.txt
1
2
3
4
2
6
2
8
9
10
​
​
示例3  根据字段数量执行不同的操作
[root@xkj /]# awk '{if (NF < 2) {print "小: " $0} else {print "大: " $0}}' test.txt
大: 1  1
大: 2  2
小: 3
小: 4
大: 5 2
小: 6
大: 7 2
小: 8
小: 9
小: 10
#字段数小于2的行前面加小 其他加大
3.7 awk实例

统计/etc/fstab文件中每个文件系统类型出现的次数

[root@xkj /]# cat /etc/fstab |awk '/^[^#]/{print}'|awk '{print $3}'|sort |uniq -c1 swap3 xfs
​

这篇关于linux 正则表达式+文本三剑客的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/992767

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo