查询第 5 列值,基于第 4 列输入,其中第 4 列由第一个文件提供 .txt

Query 5th column value, based on 4th column input, where 4th column provided by first file.txt

提问人:Wolverine adamantium 提问时间:8/14/2023 最后编辑:Renaud PacaletWolverine adamantium 更新时间:8/15/2023 访问量:95

问:

我有 2 个文件,

first file.txt
tskvdsc95
tosaocs
second file.txt
crbvdsc85;172.31.216.65&172.31.216.66;2016;tskvdsc95;172.31.240.65&172.31.240.66;3016       
crbvdsc85;172.31.216.65&172.31.216.66;2017;tskvdsc95;172.31.240.65&172.31.240.66;3017
tskvdsc195.epc.mnc009.mcc510.3gppnetwork.org;172.20.197.3;3412;tosaocs;172.20.237.70;3412       
tskvdsc195.epc.mnc009.mcc510.3gppnetwork.org;172.20.197.3;3413;tosaocs;172.20.237.69;3413

我需要查询第二个文件中的第 5 列,使用第一个文件中的数据作为第 4 列引用的输入。

贝娄是我的剧本

#!/bin/bash
input="/path/to/folder/first file.txt.txt"
while IFS=  read -r line
do
  awk 'BEGIN{FS=";"} $4=="$line" {print$5}' /path/to/folder/second file.txt | sort | uniq -c
  #echo "$line"
done < "$input"

我的脚本正在运行,结果不是我所期望的。

我的预期结果应该是:

172.31.240.65&172.31.240.66
172.20.237.70
172.20.237.69

请帮助上面的脚本中哪个部分是错误的。

提前致谢,

WF系列

bash awk while-循环

评论

0赞 Renaud Pacalet 8/14/2023
请编辑您的问题并显示给定输入的预期输出。
0赞 Kaz 8/15/2023
文件名中有一个空格;必须引用。.txt
0赞 Ed Morton 8/15/2023
...不要创建名称中带有空格的文件,这只会使您更有可能有一天被您或其他人的代码中的错误绊倒。

答:

0赞 cforler 8/14/2023 #1

以下脚本生成预期的输出。

#!/bin/sh
file1=$1
file2=$2

while IFS= read -r target <&3; do
    {
        while IFS= read -r line <&4; do
            {
                column=$(echo "$line" | cut -d ";" -f 4)  
                if [ "$column" = "$target" ]; then
                    echo "$line" | cut -d ';' -f 5
                fi
            } 3<&-
        done 4< "$file2" | sort -rnu
    } 4<&-
done 3< "$file1"

我已经解决了 Ed Morton 指出的几个问题。

评论

0赞 Ed Morton 8/18/2023
AFAIK 唯一剩下的问题是它会慢几个数量级,并且显然需要比 awk 脚本更多的代码和更复杂的代码,但您对此无能为力。
0赞 Wolverine adamantium 8/18/2023
谢谢你的回答。我的问题解决了
3赞 Renaud Pacalet 8/14/2023 #2

您显然希望避免输出中的重复。 可能是这项工作的不错选择,这要归功于它的关联数组,以及在字段中拆分输入记录的能力。awk

如果您的输入格式很简单(在引号字段中没有,每行一条记录等),您可以尝试:;

awk -F';' 'NR==FNR {a[$0];next} $4 in a {b[$5]}
  END {for(k in b) print k}' file1 file2

声明为输入字段分隔符 ()。在解析第一个文件时(仅第一个文件为 true),将每一行存储为数组 () 的键并移动到下一行 ()。在解析第二个文件时,如果第四个字段是数组 () 的键,则将第五个字段存储在数组 中。在数组 () 的所有键上的循环中并打印它们 ()。;-F';'NR==FNRaa[$0]nexta$4 in abENDbfor(k in b)print k

注意:这样可以避免输出中的重复,但不会保留输入顺序。如果您需要保留输入顺序,请编辑您的问题并添加此内容。

评论

0赞 Wolverine adamantium 8/16/2023
感谢@Renault帕卡莱特,我想要的那个工作级长。对不起,回复晚了,我正在谷歌上搜索脚本的工作原理。我可以再次要求进一步增强吗,上面的脚本可以很好地避免第 5 列中的重复,但丢失了第 5 列属于第 4 列而没有重复的信息。
0赞 Renaud Pacalet 8/16/2023
不确定我是否理解。是否也要打印第 4 列?这与预期的输出不同,但很容易做到:替换为 和 。{b[$5]}{b[$5]=$4}print kprint b[k] ";" k
0赞 Wolverine adamantium 8/16/2023
是的,按照我的预期工作。同时显示第 4 列和第 5 列。所以基本上,如果没有错误的话,将 b[$5] 打印为索引,将 $4 打印为值?非常感谢您的帮助
0赞 Renaud Pacalet 8/16/2023
就是这样。在答案中,我们只使用键,而不关心值。在这里,我们确实同时使用了两者。
4赞 Ed Morton 8/14/2023 #3

关于错误 - 请阅读 how-do-i-use-shell-variables-in-an-awk-script。但是不要为此使用每行调用 awk 的 shell 循环,只需调用 awk 一次。$4=="$line"

使用任何 awk:

$ cat tst.sh
#!/usr/bin/env bash

awk -F';' '
NR==FNR {
    first[$1]
    next
}
($4 in first) && !seen[$5]++ {
    print $5
}
' first_file.txt second_file.txt

$ ./tst.sh
172.31.240.65&172.31.240.66
172.20.237.70
172.20.237.69