根据值在 bash 中连接两个文件中的行

根据值在 bash 中连接两个文件中的行

我正在尝试使用 bash 脚本加入 2 个文件,它们如下所示:

文件1:

John (20)
Jim (30)
Adrian Lors (23)

文件2:

Jim
some jim info here
some jim other info
more jim info

John
some john info here
some john other info
more john info

Adrian Lors
some adrian info here
some adrian other info
more adrian info

我希望预期的结果看起来与此类似,但我没有运气尝试这样做:

文件3:

Jim (30)
some jim info here
some jim other info
more jim info

Adrian Lors (23)
some adrian info here
some adrian other info
more adrian info

John (20) 

some john info here
some john other info
more john info

理想情况下,我希望 file3 按括号中的数字排序,但我的主要问题是我无法加入这两个文件。如何在 shell 脚本中实现此目的?

谢谢

答案1

这可能就是您正在寻找的:

$ cat tst.awk
NR==FNR {
    val = $NF
    gsub(/^[[:space:]]+|[[:space:]]+[^[:space:]]+[[:space:]]*$/,"")
    map[$0] = val;
    next
}
FNR==1 {
    FS = OFS = "\n"
    ORS = "\n\n"
    $0 = $0
}
{
    $1 = $1 " " map[$1]
    print
}

$ awk -f tst.awk file1 RS= file2
Jim (30)
some jim info here
some jim other info
more jim info

John (20)
some john info here
some john other info
more john info

Adrian Lors (23)
some adrian info here
some adrian other info
more adrian info

答案2

使用join、GNUsedsort

join -t '#'\
  <(sed 's/ (/#(/' file1 | sort)\
  <(sed -z 's/\n/#/g; s/##/\n/g; $ s/#$//' file2 | sort)\
  | sort -t'#' -nrk2.2\
  | sed '2,$ s/^/\n/g; s/#/ /; s/#/\n/g'

在此命令中,未使用的字符#用作临时字段分隔符和换行符。

输出:

Jim (30)
some jim info here
some jim other info
more jim info

Adrian Lors (23)
some adrian info here
some adrian other info
more adrian info

John (20)
some john info here
some john other info
more john info

详细

第一个参数join

$ sed 's/ (/#(/' file1 | sort
Adrian Lors#(23)
Jim#(30)
John#(20)

将每行的最后一个空格字符替换为连接分隔符#并对结果进行排序。


第二个参数join

$ sed -z 's/\n/#/g; s/##/\n/g; $ s/#$//' file2 | sort
Adrian Lors#some adrian info here#some adrian other info#more adrian info
Jim#some jim info here#some jim other info#more jim info
John#some john info here#some john other info#more john info
  • 用于sed -z读取文件以便更轻松地替换换行符。
  • 前两个替换用于将每个名称的文本放在一行上:将每个换行符替换为一个#,将两个替换##回一个换行符。
  • 最后一个替换#在文件末尾删除(最后一个换行符)。
  • 对结果进行排序。

连接并再次排序的结果如下所示:

$ join -t '#'\
    <(sed 's/ (/#(/' file1 | sort)\
    <(sed -z 's/\n/#/g; s/##/\n/g; $ s/#$//' file2 | sort)\
    | sort -t'#' -nrk2.2
Jim#(30)#some jim info here#some jim other info#more jim info
Adrian Lors#(23)#some adrian info here#some adrian other info#more adrian info
John#(20)#some john info here#some john other info#more john info

连接第一个字段上的两个过程替换,并从位置 2 开始对第二个字段进行反向数字排序。


剩下的部分

... | sed '2,$ s/^/\n/g; s/#/ /; s/#/\n/g'

替换连接分隔符并带回换行符:

  • 在从第 2 行(空行)开始的每行开头添加换行符。
  • 将每行的第一行替换#为空格字符,并将剩余的#' 替换为换行符。

答案3

操作:

理想情况下,我希望 file3 按括号中的数字排序

尝试

$ sort -t\( -k2 file1 | awk '
FNR == NR       {X = $1;
                 sub ($1 FS, "")
                 T[X] = $0
                 next
                }
                {X = $0
                 sub (/ [^ ]*$/, "", X)
                }
X in T          {print $0, T[X] 
                }
' RS= FS="\n" file2 RS="\n" ORS="\n\n" OFS="\n" -
John (20)
some john info here
some john other info
more john info

Adrian Lors (23)
some adrian info here
some adrian other info
more adrian info

Jim (30)
some jim info here
some jim other info
more jim info

sort根据需要按“括号中的数字”对 file1 进行排序,然后读取 file2 并将其存储在以 $1 为索引的数组中,使用空行作为记录分隔符,然后使用 file1 的排序结果按索引打印数组。

相关内容