Grep/Awk:匹配行上方的匹配shell注释

Grep/Awk:匹配行上方的匹配shell注释,awk,grep,Awk,Grep,我有一个.env文件,如下所示: $ cat .env # My doc for the first var. FOO_BAR_BAZ1=val1 # My doc for the second var. # This also spans more than one line. FOO_BAR_BAZ2=val2 FOO_BAR_BAZ3=val3 $ grep -i "FOO_[^_]*_BAZ*" .env 当我运行这样的命令时: $ cat .env # My doc for t

我有一个.env文件,如下所示:

$ cat .env
# My doc for the first var.
FOO_BAR_BAZ1=val1

# My doc for the second var.
# This also spans more than one line.
FOO_BAR_BAZ2=val2

FOO_BAR_BAZ3=val3
$ grep -i "FOO_[^_]*_BAZ*" .env
当我运行这样的命令时:

$ cat .env
# My doc for the first var.
FOO_BAR_BAZ1=val1

# My doc for the second var.
# This also spans more than one line.
FOO_BAR_BAZ2=val2

FOO_BAR_BAZ3=val3
$ grep -i "FOO_[^_]*_BAZ*" .env
我希望显示匹配的行,包括其前面以
#
为前缀的行


知道我该怎么做吗?

这只打印匹配行和前面的注释:

awk '/^#/{c = c $0 "\n"; next} /regex_to_match/{print c $0 "\n"} {c=""}' filename
例如:

$ awk '/^#/{c = c $0 "\n"; next} /^FOO_[^_]*_BAZ2/{print c $0 "\n"} {c=""}' .env
# My doc for the second var.
# This also spans more than one line.
FOO_BAR_BAZ2=val2
或:

工作原理
  • /^c=c$0”\n;next}

    如果此行以
    #
    开头,则将其添加到带有尾随换行符的字符串变量
    c
    。然后跳过其余命令并跳到下一行

  • /regex\u to\u match/{print c$0”\n}

    如果此行与正则表达式匹配,则打印注释
    c
    、当前行
    $0
    ,并用一个额外的换行符分隔项目,
    \n
    。如果您不喜欢额外的换行符,可以将其删除

  • c=”“

    如果我们到达这里,那么这一行不是另一个注释行,因此我们到达了注释块的末尾。为了准备下一个注释块,
    c
    被设置为空字符串

变异 此版本不区分大小写,还允许在脚本的命令行上指定正则表达式:

$ cat script
#!/bin/sh
awk -v x="$1" 'BEGIN{IGNORECASE=1} /^#/{c = c $0 "\n"; next} $0 ~ "^Foo_"x"_" {print c $0 "\n"} {c=""}' .env
作为正在使用的此脚本的示例:

$ sh script 'BA.*'
# My doc for the first var.
FOO_BAR_BAZ1=val1

# My doc for the second var.
# This also spans more than one line.
FOO_BAR_BAZ2=val2

FOO_BAR_BAZ3=val3
全局与正则表达式
Unix有两种非常不同的模式表示方式:全局表达式和正则表达式。例如,对于globs,
BAZ*
匹配
BAZ
,后跟零个或多个其他字符。Awk不使用globs;它使用正则表达式。在正则表达式中,
BAZ*
匹配
BA
,后跟零个或多个
Z
字符。

这只打印匹配行和前面的注释:

awk '/^#/{c = c $0 "\n"; next} /regex_to_match/{print c $0 "\n"} {c=""}' filename
例如:

$ awk '/^#/{c = c $0 "\n"; next} /^FOO_[^_]*_BAZ2/{print c $0 "\n"} {c=""}' .env
# My doc for the second var.
# This also spans more than one line.
FOO_BAR_BAZ2=val2
或:

工作原理
  • /^c=c$0”\n;next}

    如果此行以
    #
    开头,则将其添加到带有尾随换行符的字符串变量
    c
    。然后跳过其余命令并跳到下一行

  • /regex\u to\u match/{print c$0”\n}

    如果此行与正则表达式匹配,则打印注释
    c
    、当前行
    $0
    ,并用一个额外的换行符分隔项目,
    \n
    。如果您不喜欢额外的换行符,可以将其删除

  • c=”“

    如果我们到达这里,那么这一行不是另一个注释行,因此我们到达了注释块的末尾。为了准备下一个注释块,
    c
    被设置为空字符串

变异 此版本不区分大小写,还允许在脚本的命令行上指定正则表达式:

$ cat script
#!/bin/sh
awk -v x="$1" 'BEGIN{IGNORECASE=1} /^#/{c = c $0 "\n"; next} $0 ~ "^Foo_"x"_" {print c $0 "\n"} {c=""}' .env
作为正在使用的此脚本的示例:

$ sh script 'BA.*'
# My doc for the first var.
FOO_BAR_BAZ1=val1

# My doc for the second var.
# This also spans more than one line.
FOO_BAR_BAZ2=val2

FOO_BAR_BAZ3=val3
全局与正则表达式
Unix有两种非常不同的模式表示方式:全局表达式和正则表达式。例如,对于globs,
BAZ*
匹配
BAZ
,后跟零个或多个其他字符。Awk不使用globs;它使用正则表达式。在正则表达式中,
BAZ*
匹配
BA
,后跟零个或多个
Z
字符。

您可以指定
-b1
-a1
在匹配前后显示一行。如果你想使它更精确,我想你必须使用<代码> SED。我确实考虑了-B和-A选项,但是行的数量有所不同。code>awk是最好的选择。您可以指定
-B1
-A1
在比赛前后显示一行。如果你想使它更精确,我想你必须使用<代码> SED。我确实考虑了-B和-A选项,但是行的数量有所不同。code>awk是个不错的选择。非常有魅力,谢谢。另外,感谢您提供解释。我已对其进行了修改,以适应不区分大小写的匹配
awk'BEGIN{IGNORECASE=1}/^#/{c=c$0“\n;next}/^FOO''1''./{print c$0}{c=”“}.env
。但是,将星号(如
BA*
)传递到脚本中,然后将其分配给
$1
,将产生
zsh:no-matches-found:BA*
@Housni非常好。我用一个例子更新了答案,将不区分大小写的命令放在脚本中。如果命令行中有不带引号的glob字符,shell将尝试展开它们。你不会想要这个的。如图所示,将模式放在单引号中,以便将其传递给awk。另外,请注意,awk的模式是正则表达式,而不是全局表达式(请参阅更新的答案)。此外,使用
/^FOO''1'''./
可能会有危险:可能会将
$1
的内容解释为awk命令,并产生意外后果。答案显示了一种更安全的方法。非常有效,谢谢。另外,感谢您提供解释。我已对其进行了修改,以适应不区分大小写的匹配
awk'BEGIN{IGNORECASE=1}/^#/{c=c$0“\n;next}/^FOO''1''./{print c$0}{c=”“}.env
。但是,将星号(如
BA*
)传递到脚本中,然后将其分配给
$1
,将产生
zsh:no-matches-found:BA*
@Housni非常好。我用一个例子更新了答案,将不区分大小写的命令放在脚本中。如果命令行中有不带引号的glob字符,shell将尝试展开它们。你不会想要这个的。如图所示,将模式放在单引号中,以便将其传递给awk。另外,请注意,awk的模式是正则表达式,而不是全局表达式(请参阅更新的答案)。此外,使用
/^FOO''1'''./
可能会有危险:可能会将
$1
的内容解释为awk命令,并产生意外后果。答案显示了一种更安全的方法。