【问题标题】:Using awk to manipulate data from two sources使用 awk 操作来自两个来源的数据
【发布时间】:2019-05-15 21:28:45
【问题描述】:

作为我团队中 CI\CD 流程的一部分,我想从包含某些资源路径的文件中生成动态命令脚本。

文件paths.txt 包含由新行分隔的路径。对于这个文件中的每一行,都应该生成一个命令,除非它以“JarPath/...”开头

示例:

JarPath/DontTouchMe.jar
path/to/some/resource/View/PutMeInScript.msgflow
path/to/some/resource/Control/MeAlso.map

文件 mapping.txt 包含一个键值对。键是要与paths.txt中的路径匹配的短语,生成的命令需要它的值。

示例:

View viewEG.bar
Control controlEG.bar

paths.txt 中的行没有排序,有些路径可以匹配 mapping.txt 中的单个值。
只应考虑与路径中第一个可能的解析匹配的 mapping.txt 文件中的第一个匹配项。我不在乎映射中后面的行是否也匹配,也不关心路径中后面的目录是否与其他行匹配。
路径上的待匹配解析不在固定位置(如第4个“/”之后)

脚本文件中的最终结果应该是:

mqsicreatebar -data ./ -b viewEG.bar -o /path/to/some/resource/View/PutMeInScript.msgflow
mqsicreatebar -data ./ -b controlEG.bar -o /path/to/some/resource/Control/MeAlso.map

由于命令行从两个源(paths.txt 和 mapping.txt 中的值对)获取数据,因此我无法将其包装到单个 awk 命令中,也无法将其通过管道传输到单个 bash 行。我写道:

pathVar="paths.txt"
touch deltaFile.txt
while IFS= read -r line
do
  awk -v var=$line" 'var ~ $1 && var !~ /^JarPath/ {print $2, " ", var ;exit}' mapping.txt >>  deltaFile.txt
done < "$pathVar"
IFS=$'\n'
awk '{print "mqsicreatebar -data ./ -b", $1, "-o", $2 }' deltaFile.txt > script.sh

嗯,它有效,但有更好的方法吗?

【问题讨论】:

  • 请注意,在写入文件之前永远不需要touch,您可以直接写入它。所以不需要touch datafile.txt,如果它不存在,`>> deltaFile.txt` 会创建它。当然,如果它确实存在,那么新数据将被附加到它上面,所以你可能想要使用rm datafile而不是touch datafile
  • View viewEG.barpath/to/some/resource/View/PutMeInScript.msgflow 有何关联?只是文件顺序?我看到了匹配的目录,但我认为这些会重复...?
  • @PaulHodges 请注意第一个 awk 命令中的 var ~ $1
  • 是的,View 匹配 .../View/...,但它们是独一无二的吗?它总是路径中的第 5 个元素吗?
  • @PaulHodges 这不是唯一的,第一次匹配很重要,请参阅 ...;在第一个 awk 上退出。它并不总是路径中的第 5 个元素。

标签: bash awk


【解决方案1】:

鉴于您在下面的评论,Only the first match in the mapping.txt file that matches the first possible parse in the path should be considered. The key dir can appear anywhere 这就是您所需要的:

$ cat tst.awk
NR==FNR {
    keys[++numKeys] = $1
    map[$1] = $2
    next
}
!/^JarPath/ {
    numDirs = split($0,dirs,"/")
    val = ""
    for (dirNr=1; (dirNr<=numDirs) && (val==""); dirNr++) {
        dir = dirs[dirNr]
        for (keyNr=1; (keyNr<=numKeys) && (val==""); keyNr++) {
            key = keys[keyNr]
            if (dir == key) {
                val = map[dir]
            }
        }
    }
    printf "mqsicreatebar -data ./ -b \047%s\047 -o \047%s\047\n", val, $0
}

$ awk -f tst.awk mapping.txt paths.txt
mqsicreatebar -data ./ -b 'viewEG.bar' -o 'path/to/some/resource/View/PutMeInScript.msgflow'
mqsicreatebar -data ./ -b 'controlEG.bar' -o 'path/to/some/resource/Control/MeAlso.map'

【讨论】:

  • 关于匹配,两个假设都是正确的。只应考虑与路径中第一个可能的解析匹配的 mapping.txt 文件中的第一个匹配项。关键目录可以出现在任何地方。感谢您的宝贵时间
  • 什么迫使 map[] 保留原始文件行顺序?
  • 更新前的答案不会按顺序处理您的映射文件,这就是更新的目的。 map[] 不存储任何顺序,因为它只是将键映射到值的哈希查找,keys[++numKeys] = $1 会。为了提高效率,必须有 2 个数组 - 一个用于存储键的顺序,另一个用于将键映射到它们的值。
  • 我更新了我的答案,只显示你在 cmets 中所说的实际需要的脚本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多