在变量(grep、awk、sed、pearl等)中的字符串中找到一个模式后,输出值/单词



我有一个程序,可以将数据打印到控制台中,如下所示(用空格分隔):

variable1 value1
variable2 value2
variable3 value3
varialbe4 value4

编辑:实际上输出可以是这样的:

data[variable1]: value1
pre[variable2] value2
variable3: value3
flag[variable4] value4

最后,我想搜索名称的一部分,例如variable2variable3,但只得到value2value3作为输出。EDIT:然后,这个值应该存储在一个变量中,以便在bash脚本中进行进一步处理。

我首先尝试将所有控制台输出放入一个文件中,并从那里用例如进行处理

# value3_var="$(grep "variable3" file.log | cut -d " " -f2)"

这很好用,但太慢了。我每次运行需要处理大约20个这样的变量,这在我的系统上需要大约1-2秒。此外,我还需要这样做大约500次跑步编辑:实际上,我不需要通过一次调用(例如awk)自动处理所有约20个"搜索"。如果有一种方法可以自动完成,那也没关系,但是bash脚本中的大约20个调用在这里也很好。

因此,我考虑将控制台输出直接放入一个变量中,以消除缓慢的文件访问。但这将消除换行符,这将再次使处理变得更加复杂:

# console_output=$(./programm_call)
# echo $console_output
variable1 value1 variable2 value2 variable3 value3 varialbe4 value4

编辑:实际上是这样的:

# console_output=$(./programm_call)
# echo $console_output
data[variable1]: value1 pre[variable2] value2 variable3: value3 flag[variable4] value4

我找到了这种字符串排列的解决方案,但这些似乎只适用于文本文件。至少我不能将存储在$console_output中的字符串与这些示例一起使用

如何用grep、sed和awk打印找到的模式后的下一个单词?

那么,当提供一个(长)字符串作为变量时,如何在找到的模式后输出下一个单词呢?

PS:我的系统上的grep不知道参数-p。。。

我建议使用awk:

$ cat ip.txt
data[variable1]: value1
pre[variable2] value2
variable3: value3
flag[variable4] value4
$ cat var_list
variable1
variable3
$ awk 'NR==FNR{a[$1]; next}
{for(k in a) if(index($1, k)) print $2}' var_list ip.txt 
value1
value3

要使用另一个命令的输出作为输入文件,请使用./programm_call | awk '...' var_list -,其中-将指示stdin作为输入。

然后,这个值应该存储在一个变量中,以便在bash脚本中进行进一步处理。

如果要进行进一步的文本处理,可以在awk中进行,从而避免可能较慢的bash循环。请参阅为什么使用shell循环处理文本被认为是不好的做法?详细信息。


加速建议:

  • 如果输入是ASCII,请使用LC_ALL=C awk '..'(注意,正如注释中所指出的,这并不适用于所有情况,因此您必须针对您的用例进行测试)
  • 如果可用,请使用mawk,这通常会更快。GNU awk在某些情况下可能仍然更快,因此,您必须再次针对您的用例进行测试
  • 使用ripgrep,它通常比其他grep程序更快
$ ./programm_call | rg -No -m1 'variable1S*s+(S+)' -r '$1'
value1
$ ./programm_call | rg -No -m1 'variable3S*s+(S+)' -r '$1'
value3

这里,-o选项用于仅获取匹配的部分。-r用于通过将匹配部分替换为捕获组中的值来仅获得所需的文本。-m1选项用于在找到第一个匹配后停止搜索输入。-N用于禁用行号前缀。

在第一次grep匹配后退出,如下所示:

value3_var="$(grep -m1 "variable3" file.log | cut -d " " -f2)"

或者使用Perl,也可以在第一次匹配后退出。这就不需要管道连接到另一个过程:

value3_var="$(perl -le 'print $1, last if /^variable3s+(.*)/' file.log)"

如果我正确理解了您的需求,那么喂食怎么样CCD_ 21直接输出到CCD_解析shell变量。

./programm_call | awk '
# the following block is invoked line by line of the input
{
a[$1] = $2
}
# the following block is executed after all lines are read
END {
# please modify the print statement depending on your required output format
print "variable1 = " a["variable1"]
print "variable3 = " a["variable3"]
}'

输出:

variable1 = value1
variable3 = value3

正如您所看到的,脚本可以同时处理所有(~20)个变量。

[更新]

假设,包括提供的信息:

  • CCD_ 23打印大约50对";可变值">
  • variablevalue由空白字符分隔
  • CCD_ 26可以被CCD_ 27和CCD_
  • variable后面可能跟有:
  • 我们对大约50对中多达20个变量感兴趣
  • 我们一次只使用20个变量中的一个
  • 我们不希望在只访问一个变量时调用./program_call
  • 我们希望从bash脚本中访问变量值
  • 我们可以使用关联数组通过变量名获取值

然后直接在bash脚本:

#!/bin/bash
declare -A hash                 # declare an associative array
while read -r key val; do       # read key (variable name) and value
key=${key#*[}               # remove leading "[" and the characters before it
key=${key%:}                # remove trailing ":"
key=${key%]}                # remove trailing "]"
hash["$key"]="$val"         # store the key and value pair
done < <(./program_call)        # feed the output of "./program_call" to the loop
# then you can access the values via the variable name here
foo="${hash["variable2"]}"      # the variable "foo" is assigned to "value2"
# do something here
bar="${hash["variable3"]}"      # the variable "bar" is assigned to "value3"
# do something here

有人批评CCD_ 32处理文本行太慢,但在这种情况下,我们只处理大约50行。我测试了一个模拟生成50行,用上面的脚本处理输出,将整个过程重复1000次。它在几秒钟内就完成了。(意味着一批在几毫秒内结束。)

这就是如何高效而稳健地完成工作(您的方法和所有其他当前答案将导致您想要搜索的变量的某些输入和某些值的错误匹配):

$ cat tst.sh
#!/usr/bin/env bash
vars='variable2 variable3'
awk -v vars="$vars" '
BEGIN {
split(vars,tmp)
for (i in tmp) {
tags[tmp[i]":"]
tags["["tmp[i]"]"]
tags["["tmp[i]"]:"]
}
}
$1 in tags || ( (s=index($1,"[")) && (substr($1,s) in tags) ) {
print $2
}
' "${@:--}"

$ ./tst.sh file
value2
value3

$ cat file | ./tst.sh
value2
value3

请注意,唯一的循环是在BEGIN部分,它用输入中可能与变量列表匹配的字符串填充哈希表(tags[]),这样在处理输入时就不必循环,它只需对当前的$1进行哈希查找,这将非常高效且稳健(例如,在部分匹配甚至regexp元字符时不会失败)。

如图所示,无论输入来自文件还是管道,它都会起作用。如果这还不是你所需要的全部,那么编辑你的问题以澄清你的要求,并改进你的例子,以显示这并不能达到你想要的效果。

最新更新