在awk中使用带有转义字符的bash变量从文件中提取行

day*_*yne 5 bash awk

我正在编写一个 bash 脚本(只是学习 bash)来基于两种模式从文件中提取一些行。第一个模式只是一个以冒号结尾的句子。第二个模式是*重复 N(在本例中为 58)次。

一个示例文件:

lines I don not want
lines I don not want
lines I don not want

A sentence here:
********************************************************
lines I want
lines I want
lines I want
**********************************************************

lines I don not want
lines I don not want
lines I don not want
Run Code Online (Sandbox Code Playgroud)

期望的输出:

A sentence here:
********************************************************
lines I want
lines I want
lines I want
**********************************************************
Run Code Online (Sandbox Code Playgroud)

如果我在对 awk 的调用中显式输入A sentence here\*58 次,我可以使脚本工作,但是为了清洁和可读性,我更愿意执行以下操作:

pat1="A sentence here"
pat2=`printf -- '\*%.s' {1..58} ; echo`
pat2=${pat2//\\/\\\\}
awk -v pat1="${pat1}" -v pat2="${pat2}" '/{pat1}/ {p=1}; p; /{pat2}/ {p=0}' $1
Run Code Online (Sandbox Code Playgroud)

其中第一个位置变量是输入文件。上面的代码什么都不返回。我最初在没有替换的情况下尝试了它pat2,但收到了警告:

awk: warning: escape sequence `\*' treated as plain `*'
Run Code Online (Sandbox Code Playgroud)

我将不得不运行此命令数千次,并且理想情况下会喜欢一个既干净又高效的解决方案。我不依赖于使用awk

编辑:

我刚刚注意到,即使我在 awk 中手动输入模式,我仍然收到警告消息。我可能没有正确地将变量传递给 awk。

Sté*_*las 9

这里有几个选项:

  • pat1, pat2 被视为正则表达式:

    pat1="A sentence here"
    pat2='\*{58}'
    export pat1 pat2
    awk '$0 ~ ENVIRON["pat1"], $0 ~ ENVIRON["pat2"]'
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,4.0.0 之前的mawk和 版本gawk不支持{}扩展正则表达式运算符。对于旧版本的gawk,您可以传递POSIXLY_CORRECT环境变量以使其识别它。

    在这里使用该start-condition, end-condition [{action}]方法,但您可以对p标志方法执行相同的操作。

  • pat1, pat2 作为固定字符串处理:

    pat1="A sentence here"
    pat2=$(printf '*%.0s' {1..58})
    export pat1 pat2
    awk 'index($0, ENVIRON["pat1"]), index($0, ENVIRON["pat2"])'
    
    Run Code Online (Sandbox Code Playgroud)

    在这里,index()对于搜索(变量内容)在任何地方干草堆(当前记录(行)),但你也可以做一个简单的全行比较:

    awk '"" $0 == ENVIRON["pat1"], "" $0 == ENVIRON["pat2"]'
    
    Run Code Online (Sandbox Code Playgroud)

    ""即使在$0ENVIRON["patx"]都是数字的情况下也强制进行字符串比较)。

避免使用-v如通过,可能包含反斜杠字符的数据awk做了一些C转义序列(\n\b\\...)对他们的处理,你需要逃避反斜杠(与GNU awk4.2或以上,价值与开始@/和结束/也是一个问题)。传递的变量也是如此awk '...code...' awkvar="$shellvar"。使用ENVIRONARGV代替。

有关更多详细信息,请参阅相关问题的答案