【问题标题】:regex: Reuse matched result to get another match of the same output?正则表达式:重用匹配结果以获得相同输出的另一个匹配?
【发布时间】:2018-07-12 02:33:44
【问题描述】:

我有一个返回输出的命令:

$ show
file 1  banana
file 3  apple
file 2  watermelon
file 0  tomato

file name 0=abc 1=def
          2=ghi 3=jkl

使用给定的文件名,我想找到相关的单词。例如,ghi 将匹配 watermelon

我可以将文件号与sed 匹配并重复使用结果:

$ filenum=$(show | sed -n 's/.*\<\([0-9]*\)=ghi\>.*/\1/p')
$ show | sed -n 's/file '"$filenum"'  \([a-z]*\)/\1/p'
watermelon

show 的输出计算起来可能很长,所以我想避免调用它两次。也可以将输出存储在一个变量中并做同样的事情:

$ out=$(show)
$ filenum=$(echo "$out" | sed -n 's/.*\<\([0-9]*\)=ghi\>.*/\1/p')
$ echo "$out" | sed -n 's/file '"$filenum"'  \([a-z]*\)/\1/p'
watermelon

但我想用最少的命令来做到这一点。

仅调用sedawk 或任何类似实用程序是否可以达到相同的结果?

编辑我想要一个命令magic-command,对于给定的文件名,在show 命令的输出中打印相关的单词。例如:

$ show | magic-command "ghi"
watermelon
$ show | magic-command "abc"
tomato
$ show | magic-command "def"
banana

show 命令的格式如下:

file <filenum>  <word>
...

file name <filenum>=<filename> ...

编辑 2 感谢您的回答,我以前从未使用过awk,所以感谢您,我学到了很多东西!所以我对它们进行了修补,最终得到了以下结果:

$ cat magic-command.sh
#!/bin/sh
awk '
# Match the `<filenum>=<filename>` using the given <filename>
# to find to <filenum>
match($0, /([0-9]*)='"$1"'/, out ) {
  filenum=out[1]
}
# Fill n2name using the `file <filenume>  <word>` lines
/\<file [0-9]*\>/ {
  n2name[$2]=$3
}
END {
  print n2name[filenum]
}'

然后:

$ show | ./magic-command.sh "ghi"
watermelon

【问题讨论】:

  • 欢迎来到 SO,这是 file name 0=abc 1=def 2=ghi 3=jkl 是一个 shell 变量吗?你能详细说明一下吗?
  • @RavinderSingh13 谢谢! file name 0=abc 1=def 2=ghi 3=jklshow 命令输出的一部分。第一个代码块中除了第一行之外的所有内容都是show 的输出。
  • 如果给定的解决方案对您有用,请告诉我?

标签: regex shell awk sed


【解决方案1】:
$ cat tst.awk
/=/ {
    for (i=1; i<=NF; i++) {
        if ( split($i,f,/=/) == 2 ) {
            name2nr[f[2]] = f[1]
        }
    }
    next
}
{ nr2text[$2] = $3 }
END { print nr2text[name2nr[name]] }

使用cat file(其中file 包含您问题中提供的show 的输出)代替show

$ cat file | awk -v name='ghi' -f tst.awk
watermelon

如果文件名可以包含= 或空格,则上述(以及其他当前发布的答案和任何其他明显的解决方案)将失败。如果发生这种情况,那么您需要告诉我们如何识别文件名,而不是字段和/或赋值语句。

【讨论】:

  • 嗨,Ed,非常感谢您的回答,这很有趣!不,&lt;filename&gt; 不会包含任何 = 或空格。很抱歉,我的问题中缺少一些信息:包含= 的唯一行是&lt;filenum&gt;=&lt;filename&gt; 行,但也有比file &lt;filenum&gt; &lt;word&gt; 更多的行(但它们不是以file 开头) .所以对于倒数第二个块,我会将/^file/ 作为模式。
  • 如您所见,如果您阅读了我的答案,它不依赖于以 file 或其他任何开头的行。我希望它会按原样为您工作-您尝试过吗?如果您发布的示例输入不能充分代表您的真实输入文件,那么显然,请修复它,这样我们就不会猜测输入可能是什么以及如何最好地处理它。
  • 确实,即使没有 /file/ 模式,您的代码也可以工作,但我认为避免在 nr2text 中进行不必要的分配会更好!因为输出非常复杂,所以我更喜欢保持简单。这也是为什么我没有编辑我的示例,只是在您的答案中添加评论,否则这正是我所要求的!
【解决方案2】:

编辑:根据 OP 添加解决方案,OP 需要将其与另一个程序一起运行,然后尝试跟随。

cat script.ksh
your_command | awk  -v command="$1" -F' +|=' '
/^file/ && !/^file name/{
  a[$2]=$NF
}
/^file name/{
  for(i=3;i<=NF;i+=2){
    array[$i]=$(i+1)}
}
/^ +/{
  for(j=2;j<=NF;j+=2){
    array[$j]=$(j+1)}
}
END{
  for(i in array){
    if(array[i]==command){  print array[i],a[i]  }
}}'

以下将是我们运行脚本时的输出。

./script.ksh "ghi"
ghi watermelon


您的帖子还有很多问题不清楚,完全基于您发布的内容,请尝试关注一次(仅根据您的示例完全显示)。

awk -F' +|=' '
FNR==NR{
  if($0 ~ /file name/){
    for(i=3;i<=NF;i+=2){
      array[$i]=$(i+1)
    }
    getline
    for(j=2;j<=NF;j+=2){
      array[$j]=$(j+1)
    }
  }
  next
}
($2 in array){
  print array[$2],$NF
}'   Input_file  Input_file

输出如下。

def banana
jkl apple
ghi watermelon
abc tomato
ghi jkl

考虑到您的 show 函数在此处输出到 Input_file 并且我在此处读取 Input_file 2 次。

【讨论】:

  • 感谢您的回答!因此,如果不进行预处理(在这里,将show 的输出放在单独的文件中),似乎不可能实现我想要的。您能告诉我我的帖子中有哪些不清楚的地方吗?
  • @anonom,您的预期输出和获得它的条件都不清楚,请重新表述您的问题,然后让我们知道。
  • 感谢您的宝贵时间。我不知道为什么你没有发现我的预期输出明确:我想要一个magic-command 让我有这个:show | magic-command "ghi" 返回watermelon。这就是我写的尝试中发生的事情。我将尝试添加另一个示例,但我看不到缺少什么。
  • @anonom,现在检查我的 EDIT 解决方案,让我知道这是否有帮助?另请参阅此链接,一旦有人回复您的帖子,我们应该怎么做,stackoverflow.com/help/someone-answers
  • 感谢您的新解决方案。由于我是 SO 新手(声誉低于 15),因此我的投票不会公开显示。预期的输出并不完全相同,我认为最后的打印应该只是print a[i]。否则,太棒了!谢谢你的帮助。在接受一个作为答案之前,我需要比较我得到的两个答案。我需要了解更多关于awk的信息!
猜你喜欢
  • 2019-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 2016-11-10
  • 1970-01-01
  • 2016-06-14
相关资源
最近更新 更多