awk 查找/打印包含多个模式的段落

问题描述 投票:0回答:1

要求:

提取包含 2 个或更多搜索词的文本块,类似于 [ awk ] 中的 [ AND ] 逻辑运算符。

最好在 bash/zsh 函数中作为 awk 运行(但也可以使用独立的 awk 脚本),以正则表达式样式接受输入/参数:

[ A|B|C ] = 返回包含“A”或“B”或“C”的块

[ A&B&C ] = 返回包含所有“A”、“B”和“C”的块

背景: 块之间至少用 5 个新行分隔。

额外: 突出显示搜索匹配项。

输入

给定 [ veganPackage.txt ] 输入文件:

1. Fruits 
Apple
Banana
Honey
   - tasty combo but too many sugars
   - Low prep time
   - bad for teeth, cavity warning 




2. Drinks
Apple Juice
   - served cold and ripe

Add Kiwi
   - peel first

Banana Smoothie
   - tastes good
   - fast power up



3. Veggies
Frillice
Cucumber 
Tomato



想要

输入 要打印的块 给单词上色
苹果|香蕉 水果、饮料 苹果、香蕉
苹果|香蕉|褶边 水果、饮料、蔬菜 苹果、香蕉、褶边
苹果香蕉 水果、饮料 苹果、香蕉
苹果&番茄 没什么 没什么
猕猴桃&香蕉 饮料 猕猴桃、香蕉(仅限饮料)

尝试过

Bash 功能

命名为 [ searchBlock ]

searchBlock ()
{
...

awk \
  -v RS='\n{4}' \
  -v ORS='\n***\n***\n' \
  -v color=$colorOut \
  -v colorReset=$colorReset \
  -v search=$(echo "$searchTerm" | perl -pe 's/(?<!\\)&+/\/&&\//g and s/^/\//g and s/(.)(?=$)/\1\//g') searchTerm \
  -v searchAND=$(echo $searchTerm | perl -pe 's/&+/|/g') '$0~search{gsub(searchAND,color"&"colorReset);print}' $file |
  vim - -c "/$searchTerm" \
        -c ':AnsiEsc' \
        -c 'highlight ColorReverse gui=reverse cterm=reverse' \
        -c ":match ColorReverse /$searchTerm/"
}

调用示例:

 searchBlock -s 'Apple|Banana' veganPackage.txt

理由:

  • if OR 模式为 [ | ] 在输入中,进行正则匹配
  • 如果输入中 AND 模式为 [ & ],则保留 [ | ] 用于着色,但更改为 [ && ] 用于图案行进
  • 将操作数作为参数的一部分

瓶颈

  1. 如果我手动喂食
    '/Apple/&&/Kiwi/{gsub(/(Apple|Kiwi)/,color"&"colorReset);print}' veganPackage.txt
    ,则按预期输出:
\*\*\*
\*\*\*

2. Drinks

Apple Juice

   - served cold and ripe

Add Kiwi

   - peel first

Banana Smoothie

   - tastes good

   - fast power 
up

\*\*\*
\*\*\*

但是,使用

'$0 ~ search{gsub(searchAND,color"&"colorReset);print}
,[ AND ] 模式#失败(没有打印任何内容)

(不是我过滤/搜索的),但突出显示/着色是正确的)

  • $0 ~ search
    = 对于 awk [ search ] 变量中包含模式的每个块,

  • {gsub(searchAND,color"&"colorReset);print}
    = 打印由 ANSI 转义序列包围的搜索文本的全局替换

    • [ & ] 作为正则表达式特定语法被双引号引用(不要与 awk 的 AND 模式匹配中的 [ && ] 混淆))

看来

$0 ~ /Apple/&&Kiwi/
不与我合作。

测试

输入 代码片段 结果 期待
苹果|猕猴桃
$0~search
水果、饮料 水果、饮料
苹果&猕猴桃
$0~search
没什么 饮料
苹果|猕猴桃
search
整个文件 饮料、水果
苹果&猕猴桃
search
整个文件 饮料
苹果&&猕猴桃
search
整个文件 饮料
/苹果/&&/猕猴桃/
$0~search
没什么 饮料
苹果&&猕猴桃
$0~search
没什么 饮料

额外问题

  1. 如何在awk中调试以显示逐行执行中的变量变化+函数返回值?

  2. awk 是否具有与 bash 的 ShellCheck 等效的语法检查器?

  3. 是否有比 awk 更直观的文本处理/过滤工具(不是 sed,不是 perl)?

bash awk text-processing
1个回答
0
投票

假设:

  • 您能够(在
    bash
    中)将各种输入解析/重新格式化为
    awk
  • 可接受的格式

一般方法:

  • gsub/regex
    作为
    -v variable=value
    子句传递
  • 通过将字符串拼凑在一起来传递搜索正则表达式以构建(即时)
    awk
    脚本

为了简化流程,我们将使用以下内容:

$ cat simple.dat
line_1 - Apple
line_2 - Banana
line_3 - Kiwi Cherry Apple
line_4 - Apple Kiwi
line_5 - Kiwi

我们将使用

bash/for
循环来测试一些不同的搜索正则表达式(
gsub()
正则表达式对于所有 3 个搜索正则表达式都是相同的):

for search_regex in "/Apple/ && /Kiwi/" "/Apple|Kiwi/" "/Apple/ || /Kiwi/"
do
    printf "\n########## search : ${search}\n\n"

    awk -v gsub_regex="Apple|Kiwi" ' 
    BEGIN { filler=ignore }
    '"${search_regex}"' { gsub(gsub_regex,"__&__") }
    1
    END   { filler=ignore }
    ' sample.dat

done

注意:这里我假设您可以将各种输入格式解析为两个正则表达式变量的其中一种格式

地点:

  • awk
    脚本的第一部分:
    'BEGIN { filler=ignore } '
    
    
  • awk
  • 脚本的第二部分:
    "${search)regex}"
    ;必须用双引号括起来
    awk
  • 脚本的第三部分:
  • ' { gsub(gsub_regex,"__&__") } 1; END { filler=ignore }' sample.dat
    
    
    单引号(第 1/3 部分)和双引号(第 2 部分)之间不能有任何空格
  • 试驾:
########## search : /Apple/ && /Kiwi/ line_1 - Apple line_2 - Banana line_3 - __Kiwi__ Cherry __Apple__ line_4 - __Apple__ __Kiwi__ line_5 - Kiwi ########## search : /Apple|Kiwi/ line_1 - __Apple__ line_2 - Banana line_3 - __Kiwi__ Cherry __Apple__ line_4 - __Apple__ __Kiwi__ line_5 - __Kiwi__ ########## search : /Apple/ || /Kiwi/ line_1 - __Apple__ line_2 - Banana line_3 - __Kiwi__ Cherry __Apple__ line_4 - __Apple__ __Kiwi__ line_5 - __Kiwi__


© www.soinside.com 2019 - 2024. All rights reserved.