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】:

使用sedsort,你可以试试这个

$ 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变量字符串处理

如何从文本图像中删除虚线带?

ActionScript 3 删除ascii文本格式

删除ascii文本格式

bash

在 UITextView 中以大写形式显示文本并从 shouldChangeTextIn 中获取新文本,以保持原始文本和输入文本的大小写