首页 > 解决方案 > 用相应列中提供的文件的数字相应第 n 行替换两个不同列上第 n 次出现的 'foo' 和 'bar'

问题描述

我有一个source.txt如下所示的文件,其中包含两列数据。source.txt 的列格式包括[ ]方括号),如我的source.txt

[hot] [water]
[16] [boots and, juice]

我有另一个target.txt文件,其中包含空行以及每行末尾的句号:

the weather is today (foo) but we still have (bar). 

= (

the next bus leaves at (foo) pm, we can't forget to take the (bar).

我想用 的第一列的“相应内容”替换第 n 行,foo并用第二列的“相应内容”替换第 n 行。target.txtsource.txtbartarget.txtsource. txt

我试图搜索其他来源并了解我将如何做到这一点,起初我已经有一个命令用于替换“用所提供文件的数字相应的第 n 行替换每第 n 次出现的 'foo'”但我不能适应它:

awk 'NR==FNR {a[NR]=$0; next} /foo/{gsub("foo", a[++i])} 1' source.txt target.txt > output.txt;

我记得看到过一种使用 gsub 包含两列数据的方法,但我不记得到底有什么区别。

编辑帖子:有时在它们之间=和target.txt 文本中读取一些符号。我添加了这个符号,因为如果这些符号在文件中,一些答案将不起作用()target.txt

注意:行数以及此文件中 andtarget.txt的出现次数可能会有所不同,我只是展示了一个示例。但是每行中和的出现次数分别为1。barfoofoobar

标签: stringawkreplacegsubtext-processing

解决方案


使用您显示的示例,请尝试以下答案。用 GNU 编写和测试awk

awk -F'\\[|\\] \\[|\\]' '
FNR==NR{
  foo[FNR]=$2
  bar[FNR]=$3
  next
}
NF{
  gsub(/\<foo\>/,foo[++count])
  gsub(/\<bar\>/,bar[count])
}
1
' source.txt FS=" " target.txt

说明:为上述添加详细说明。

awk -F'\\[|\\] \\[|\\]' '       ##Setting field separator as [ OR ] [ OR ] here.
FNR==NR{                        ##Checking condition FNR==NR which will be TRUE when source.txt will be read.
  foo[FNR]=$2                   ##Creating foo array with index of FNR and value of 2nd field here.   
  bar[FNR]=$3                   ##Creating bar array with index of FNR and value of 3rd field here.
  next                          ##next will skip all further statements from here.
}
NF{                             ##If line is NOT empty then do following.
  gsub(/\<foo\>/,foo[++count])  ##Globally substituting foo with array foo value, whose index is count.
  gsub(/\<bar\>/,bar[count])    ##Globally substituting bar with array of bar with index of count.
}
1                               ##printing line here.
' source.txt FS=" " target.txt  ##Mentioning Input_files names here.


编辑:添加以下解决方案也将处理[...]源中出现的 n 次并在目标文件中匹配它们。由于这是 OP(在评论中确认)的工作解决方案,因此在此处添加此内容。当 source.txt 包含 & 时,也公平警告这将失败。

awk '
FNR==NR{
  while(match($0,/\[[^]]*\]/)){
    arr[++count]=substr($0,RSTART+1,RLENGTH-2)
    $0=substr($0,RSTART+RLENGTH)
  }
  next
}
{
  line=$0
  while(match(line,/\(?[[:space:]]*(\<foo\>|\<bar\>)[[:space:]]*\)?/)){
    val=substr(line,RSTART,RLENGTH)
    sub(val,arr[++count1])
    line=substr(line,RSTART+RLENGTH)
  }
}
1
' source.txt target.txt

推荐阅读