【问题标题】:How to use awk or sed to combine match content from two files如何使用 awk 或 sed 组合来自两个文件的匹配内容
【发布时间】:2022-10-04 18:06:44
【问题描述】:

我有两个文件,file1 和 file2
我需要用file1的每一行搜索file2,并在匹配后将它们以另一种形式放在一起
我的进步:

awk 'FNR==NR{ids[$0]=$0;next}{for(id in ids){if($0 ~ "\\y"id"\\y"){print "- name:"id; print "  version: " ; print}}}' file1 file2

文件1:

attr-2.4.48
bzip2-1.0.8
curl-7.71.1
dnsmasq-2.86
dropbear-2022.82
elfutils-0.179
ethtool-5.4

文件2:

  url: https://sourceforge.net/projects/lzmautils/files/xz-5.2.5.tar.gz/download
  url: http://download.savannah.nongnu.org/releases/attr/attr-2.4.48.tar.gz
  url: https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz
  url: https://curl.se/download/curl-7.71.1.tar.bz2
  url: https://sourceware.org/elfutils/ftp/0.179/elfutils-0.179.tar.bz2
  url: https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/snapshot/ethtool-5.4.tar.gz

输出

- name: attr
  version: 2.4.48
  url: http://download.savannah.nongnu.org/releases/attr/attr-2.4.48.tar.gz
- name: bzip2
  version: 1.0.8
  url: https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz
- name: curl
  version: 7.71.1
  url: https://curl.se/download/curl-7.71.1.tar.bz2
- name: dnsmasq
  version: 2.86
  url:
- name: dropbear
  version: 2022.82
  url:
- name: elfutils
  version: 0.179
  url: https://sourceware.org/elfutils/ftp/0.179/elfutils-0.179.tar.bz2
- name: ethtool
  version: 5.4
  url: https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/snapshot/ethtool-5.4.tar.gz

【问题讨论】:

  • 下面有四个正确的答案,我只能从中检查一个。它们都是很好的答案,请参考它们作为您的偏好
  • 我想只是通过在一个非常大的数据集上运行这些解决方案来运行一个基准测试,然后看看哪个会产生快速的结果。

标签: awk sed


【解决方案1】:

这个awk 应该为您使用 2 个不同的字段分隔符,用于 2 个输入文件:

awk '
FNR == NR {
   u = $0
   sub(/(.[a-z][[:alnum:]]*)+(/[^/]+)?$/, "")
   a[$NF] = u
   next
}
{
   print "- name:", $1
   print "  version:", $2
   print "  " ($0 in a ? a[$0] : "url:")
}' FS='/' file2 FS='-' file1

输出:

- name: attr
  version: 2.4.48
  url: http://download.savannah.nongnu.org/releases/attr/attr-2.4.48.tar.gz
- name: bzip2
  version: 1.0.8
  url: https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz
- name: curl
  version: 7.71.1
  url: https://curl.se/download/curl-7.71.1.tar.bz2
- name: dnsmasq
  version: 2.86
  url:
- name: dropbear
  version: 2022.82
  url:
- name: elfutils
  version: 0.179
  url: https://sourceware.org/elfutils/ftp/0.179/elfutils-0.179.tar.bz2
- name: ethtool
  version: 5.4
  url: https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/snapshot/ethtool-5.4.tar.gz

【讨论】:

  • 网址重复
  • url is duplicated 是什么意思?显示输出的哪一部分与您的预期输出不匹配?
【解决方案2】:

sed 'h;s/-/ version: /;s/^/- name: /p;g;s/-.*//;s/^/grep /;s/$/ file2/e' file1 | sed 's/^$/ url:/'

  • 使用 sed 到 h 保存来自 file1 的原始罚款
  • s/-/ version: /;s/^/- name:/p 打印版本/名称
  • g再次获取原行
  • s/^/grep /;s/$/ file2/e 使用 s///e 创建了一个 grep 命令并执行它
  • | sed 's/^$/ url:/'清理空行

基本上用 sed 循环 file1 的行,用 s///e 调用 grep。

【讨论】:

  • 我忍不住要挑最短的,谢谢史蒂夫
【解决方案3】:

仅使用您显示的示例,在 GNU awk 中,请尝试遵循 awk 代码;在 GNU awk 中编写和测试应该可以在它的任何版本中工作。

awk '
FNR==NR{
  arr1[$1]=$2
  next
}
{
  for(i in arr1){
    if(index($0,i)){
      arr2[i]
      print "- name: " i ORS "  version: " arr1[i] ORS  $0
      break;
    }
  }
}
END{
  for(i in arr1){
    if(!(i in arr2)){
      print "- name: " i ORS "  version: " arr1[i] ORS "  url:"
    }
  }
}
' FS="-" file1 file2

【讨论】:

  • 这是合乎逻辑的,读起来很清楚,谢谢!
【解决方案4】:

您可以使用cutgrep 在一个小的shell 脚本中自然地完成您想要的操作。

我们可以使用sed 代替cutgrep 组合,得到一个像这样的shell 脚本:

cat "file1" | while read prginfo
do
    name="${prginfo%%-*}"
    version="${prginfo##*-}"
    url="$(sed -n "/${prginfo}/ {s/url: //;p}" file2)"
    printf -- "- name: %s
  version: %s
  url: %s
" "$name" "$version" "$url" 
done

我们遍历 file1 的行(由于 cat|while read)。

名称和版本部分是从 file1 的行中解析的shell参数扩展.

url 通过sed 解析:

  • -n 用于抑制不匹配行的输出
  • /${prginfo}/ 用于匹配行并在分支内应用进一步的 sed 指令:
    • s/url: //;p} 替换“url:”并打印修改后的行
  • 我们可以用url=$(grep "$prginfo" "$2" | cut -d -f2) 替换这一行

这比第一次读取和存储 file2 短一点。但如果这些文件很大,可能需要更长的时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 2015-08-01
    • 2019-11-03
    • 1970-01-01
    相关资源
    最近更新 更多