bash 文本处理以删除 ascii 并从结果中获取唯一行
Posted
技术标签:
【中文标题】bash 文本处理以删除 ascii 并从结果中获取唯一行【英文标题】:bash text processing to remove ascii and get unique lines from the result 【发布时间】:2021-11-21 10:40:13 【问题描述】:在linux中,下面的命令
terraform providers
输出结果如下
.
├── provider[xxx.com/edu/xxxvenafi] 1.2.0
├── provider[registry.terraform.io/hashicorp/kubernetes] 2.3.2
├── provider[xxx.com/edu/xxxsmaas] 1.0.1
├── provider[registry.terraform.io/hashicorp/aws]
├── module.standard_deployment
│ ├── provider[xxx.com/edu/xxxsmaas] 1.0.1
│ ├── provider[xxx.com/edu/xxxvenafi] 1.2.0
│ ├── provider[registry.terraform.io/hashicorp/kubernetes]
│ └── provider[registry.terraform.io/hashicorp/local]
└── module.standand_ingress
├── provider[registry.terraform.io/hashicorp/kubernetes]
├── provider[xxx.com/edu/xxxsmaas] 1.0.1
├── provider[xxx.com/edu/xxxvenafi] 1.2.0
└── provider[registry.terraform.io/hashicorp/aws]
Providers required by state:
provider[xxx.com/edu/xxxsmaas]
provider[xxx.com/edu/xxxvenafi]
provider[registry.terraform.io/hashicorp/aws]
provider[registry.terraform.io/hashicorp/kubernetes]
从输出中删除这些树结构的最佳方法是什么? 最终目标是仅列出以下唯一行,
provider[xxx.com/edu/xxxvenafi] 1.2.0
provider[xxx.com/edu/xxxsmaas] 1.0.1
【问题讨论】:
为什么预期输出中缺少provider[registry.terraform.io/hashicorp/kubernetes] 2.3.2
?
【参考方案1】:
$ awk '/[0-9]$/ && sub(/[^[:alpha:]]+/,"") && !seen[$0]++' file
provider[xxx.com/edu/xxxvenafi] 1.2.0
provider[registry.terraform.io/hashicorp/kubernetes] 2.3.2
provider[xxx.com/edu/xxxsmaas] 1.0.1
或者如果你真的只想要在评论中说的以 1.0.1 或 1.2.0 结尾的行:
$ awk '/ 1\.((0\.1)|(2\.0))$/ && sub(/[^[:alpha:]]+/,"") && !seen[$0]++' file
provider[xxx.com/edu/xxxvenafi] 1.2.0
provider[xxx.com/edu/xxxsmaas] 1.0.1
【讨论】:
【参考方案2】:使用sed
和sort
,你可以试试这个
$ sed -E 's/.*(provider.*)/\1/g;/^[a-z]/!d' input_file | sort -u
provider[registry.terraform.io/hashicorp/aws]
provider[registry.terraform.io/hashicorp/kubernetes]
provider[registry.terraform.io/hashicorp/kubernetes] 2.3.2
provider[registry.terraform.io/hashicorp/local]
provider[xxx.com/edu/xxxsmaas] 1.0.1
provider[xxx.com/edu/xxxvenafi] 1.2.0
然而,这可能不是最有效的。
编辑
取自 Hai Vu 的评论,这是一个适用于 OP 的 grep 替代方案。
terraform providers | grep -o 'provider.*[0-9][^]]*$' | sort -u
【讨论】:
我喜欢这个解决方案。sed
命令的替代方法是 grep -o 'provider.*$'
所以terraform providers | grep xxx.com | grep -o 'provider.*$' | sort -u
我得到的输出为provider[fid.com/edu/fidsmaas] provider[fid.com/edu/fidsmaas] 1.0.1 provider[fid.com/edu/fidvenafi] provider[fid.com/edu/fidvenafi] 1.2.0
现在我只想保留与版本有关的行
使用sed
,您可以组合过滤器:terraform providers | sed -n 's/.*\(provider.*xxx.com.*\)/\1/p' | sort -u
我现在很接近,但我只想保留版本(1.0.1 或 1.2.0)的行。有了 Walter 和 Hatless 给出的,输出也有没有版本的行。我用我想要的输出更新了原始帖子。
@user2068179 terraform providers | grep -o 'provider.*[0-9][^]]*$' | sort -u
【参考方案3】:
使用 awk:
terrraform providers |
awk 'BEGIN FS="provider"
/xxx.com/ && NF==2 printf("%s%s\n", FS, $2)' |
sort -u
或避免调用sort
:
terrraform providers |
awk 'BEGIN FS="provider"
/xxx.com/ && NF==2 a[$2]
END
for (key in a)
printf("provider%s\n", key)
'
【讨论】:
【参考方案4】:这可能对你有用(GNU sed):
sed -nE 's/.*(provider)/\1/;ta;$!d;bb;:a;H;g
s/((\n\S+\]).*)\2[^\n]*$/\1/;h;$!d;:b;x;s/.//p' file
关闭隐式打印 -n
并打开扩展正则表达式 -E
。
匹配包含provider
的行,删除任何前导码并跳转到:a
。
如果未找到匹配项且不是最后一行,请将其删除并重复。
如果没有找到匹配项并且是最后一行,则向前跳转到:b
。
在:a
,将当前行附加到保留空间,然后将保留空间复制到当前行。
使用模式匹配,将之前的行键与当前行键进行比较,如果已添加该键,则删除当前行。
将结果复制到保持空间,如果不是最后一行,则删除并重复。
在文件末尾:b
,交换到保留空间,删除开头引入的换行符并打印结果。
【讨论】:
以上是关于bash 文本处理以删除 ascii 并从结果中获取唯一行的主要内容,如果未能解决你的问题,请参考以下文章
bash颜色显示方案bash配置文件及bash变量字符串处理
在 UITextView 中以大写形式显示文本并从 shouldChangeTextIn 中获取新文本,以保持原始文本和输入文本的大小写