Bash:根据另一列的值获取一列的值

时间:2017-03-16 17:03:55

标签: bash sorting awk unix-head

我有一个空格分隔的文件,其中包含:

5.75e-01 7.00e-1 5.52e-01 7.33e-01 ./dir1/dir2/file1.csv
5.75e-01 7.00e-1 5.42e-01 7.34e-01 ./dir1/dir2/file2.csv
5.75e-01 7.00e-1 5.72e-01 7.43e-01 ./dir2/dir2/file1.csv
5.75e-01 7.00e-1 5.22e-01 7.23e-01 ./dir2/dir2/file2.csv
5.75e-01 7.00e-1 5.02e-01 7.93e-01 ./dir3/dir2/file1.csv
5.75e-01 7.00e-1 5.12e-01 7.63e-01 ./dir3/dir2/file2.csv

我想提取第5列的值,该值对应于dir#的每个值的第3列的最大值。例如,让我们说我在谈论dir1。这对应于这些行:

5.75e-01 7.00e-1 5.52e-01 7.33e-01 ./dir1/dir2/file1.csv
5.75e-01 7.00e-1 5.42e-01 7.34e-01 ./dir1/dir2/file2.csv

我可以使用以下方法找到这些:

max_val_acc_=$(awk '$5 ~ /dir1/ { print }' filename.txt)
echo $max_val_acc

现在我想我需要通过sort来管道这个结果,然后选择head,但我无法让它运转起来。我正在寻找(dir1)的结果是:

./dir1/dir2/file1.csv

和所有目录的完整结果#:

./dir1/dir2/file1.csv
./dir2/dir2/file1.csv
./dir3/dir2/file2.csv

5 个答案:

答案 0 :(得分:1)

这是你正在寻找的吗?

$ cat tst.awk
{
    split($5,path,"/")
    dir = path[2]
    if ( !(dir in max) || ($3 > max[dir]) ) {
        max[dir] = $3
        val[dir] = $5
    }
}
END {
    for (dir in val) {
        print val[dir]
    }
}

$ awk -f tst.awk file
./dir3/dir2/file2.csv
./dir1/dir2/file1.csv
./dir2/dir2/file1.csv

答案 1 :(得分:0)

我不确定我是否理解你,但这是我理解你的方式:

awk -v s="dir1" '         # search parameter in your s
index($5,"./" s "/") {    # if your s is found in $5
    if(max==""||$3>max){  # we initialize $3 or compare to previous max
        max=$3;           # store new max
        maxv=$5           # and new mac value 
    }
}
END{ print maxv }         # print the stored max value
' file                    # oh just the file
./dir1/dir2/file1.csv

答案 2 :(得分:0)

sortawk

的另一种选择
$ sort -k5 -k3,3r file | awk -F/ '!a[$NF]++'

5.75e-01 7.00e-1 5.52e-01 7.33e-01 ./dir1/dir2/file1.csv
5.75e-01 7.00e-1 5.42e-01 7.34e-01 ./dir1/dir2/file2.csv
上面的

是针对文件名的,如果基于第一个dir名称

$ sort -k3,3r file | awk '{split($NF,d,"/")} !a[d[2]]++'

5.75e-01 7.00e-1 5.72e-01 7.43e-01 ./dir2/dir2/file1.csv
5.75e-01 7.00e-1 5.52e-01 7.33e-01 ./dir1/dir2/file1.csv
5.75e-01 7.00e-1 5.12e-01 7.63e-01 ./dir3/dir2/file2.csv

如果您只想打印目录

$ sort -k3,3r file | awk '{split($NF,d,"/")} !a[d[2]]++{print $NF}'

./dir2/dir2/file1.csv
./dir1/dir2/file1.csv
./dir3/dir2/file2.csv

答案 3 :(得分:0)

只是为了好玩 - 没有任何(awkperl之类的)编程语言

file="./data.txt"
paste -d ' ' "$file" <(cut -d/ -f2 "$file") |\
    LC_ALL=C sort -k6 -k3gr | uniq -f5 | cut -d' ' -f5

输出

./dir1/dir2/file1.csv
./dir2/dir2/file1.csv
./dir3/dir2/file2.csv

使用一些awk解决方案。正如我所说,这只是为了表现出另一种方式。

答案 4 :(得分:0)

虽然不符合您要求的输出并且与已发布的其他答案类似,但我发现此awk命令更令人难忘:

< file | sort -k3,3r | awk -F "/" '!seen[$2]++'

输出:

5.75e-01 7.00e-1 5.72e-01 7.43e-01 ./dir2/dir2/file1.csv
5.75e-01 7.00e-1 5.52e-01 7.33e-01 ./dir1/dir2/file1.csv
5.75e-01 7.00e-1 5.12e-01 7.63e-01 ./dir3/dir2/file2.csv

更一般的观点是:按大小排序整个列表(第3列)并且不用担心按目录名称排序(第5列的一部分),然后提取每个目录名称的第一个(即awk)仅打印新可见键名称)。

如果您确实希望输出只是目录名称并进行排序,那么将以下内容添加到管道链中:

| cut -d ' ' -f5- | sort