在 UNIX 中展开深度搜索

在 UNIX 中展开深度搜索

我的文件中有以下数据,其中具有用户和主管关系。

user |supervisor |id
-----|-----------|----
a    |   b       | 1
b    |   c       | 2
c    |   d       | 3
e    |   b       | 4

我想分解用户和主管之间的关系层次结构,如下所示。

user |supervisor |id
-----|-----------|----
a    |   b       | 1
a    |   c       | 1
a    |   d       | 1
b    |   c       | 2
b    |   d       | 2  
c    |   d       | 3
e    |   b       | 4
e    |   c       | 4
e    |   d       | 4 

如您所见,对于用户“a”,直接主管是“b”,但“b”再次将“c”作为其主管。所以间接地“c”也是“a”的主管,依此类推。例如,我的目标是分解给定用户的任何级别的层次结构。在 Unix 中实现此功能的最佳方法是什么?

答案1

我假设每个用户仅在输入文件(在“用户”列中)中出现一次。我进一步假设竖线 ( |) 分隔符实际上在文件中,并且它们始终通过空格与数据分隔,并且标题行是不是实际上存在。

这是使用的两遍解决方案awk。第一遍构建一个包含每个人的主管的数组;第二遍构建输出:

awk 'pass==1 { super[$1] = $3; }
     pass==2 {
                print
                user=$3
                while (super[user] != "") {
                        print $1, "|", super[user], "|", $5
                        user=super[user]
                }
             }
    ' pass=1 data pass=2 data

这将产生未正确对齐的输出。要解决这个问题,请将其通过管道传输column -t。或者我们可以在脚本中格式化输出awk;如果需要,请指定所需的格式规则。

顺便说一句,这个操作通常被称为传递闭包

答案2

复杂的awk解决方案:

awk 'NR<3{ h=(h=="")? $0 : h ORS $0 }NR>2{ uid[$1]=$5; us[$1]=$3 }
     END{ 
         print h; 
         for (u in uid) { 
             id=uid[u]; spvr=us[u]; printf("%-5s|%-11s|%-4s\n",u,spvr,id); 
             while (spvr in uid) { 
                 spvr=us[spvr]; printf("%-5s|%-11s|%-4s\n",u,spvr,id) 
             } 
         }
     }' yourfile

输出:

user |supervisor |id
-----|-----------|----
a    |b          |1   
a    |c          |1   
a    |d          |1   
b    |c          |2   
b    |d          |2   
c    |d          |3   
e    |b          |4   
e    |c          |4   
e    |d          |4 

细节:

  • NR<3{ h=(h=="")? $0 : h ORS $0 }- 捕捉标头线

  • uid[$1]=$5-用户身份关系数组

  • us[$1]=$3-用户主管关系数组

  • spvr=us[u]- 第 1 个导师对于当前的用户

  • while (spvr in uid) { ... }- 尽管导师是在用户列表,获取父级导师

答案3

我的 awk 解决方案(使用 RomanPerekhrest 的输出格式)。基本上,有两个相关的循环。首先,如果为用户处理新的主管,则必须将该主管的所有依赖项(即主管链)添加到该用户。之后,第二个循环查找所有其他用户,这些用户将当前处理的用户作为依赖项,并将当前用户的所有依赖项添加到其中:

#!/usr/bin/awk
# file process_it.awk
BEGIN {

    FS="|";
}

NR<3 {

    h=(h==""? $0 : h ORS $0)
}

NR>2 {

   gsub(/ /, "", $0)
   curr_user=$1;
   curr_supervisor=$2;
   curr_id=$3;
   print curr_user, curr_supervisor;
   arr[curr_user][curr_supervisor]++;
   id[curr_user]=curr_id;

   if(isarray(arr[curr_supervisor])) {
       for(sub_indx in arr[curr_supervisor])
           arr[curr_user][sub_indx]++;
    }
    else
        delete arr[curr_supervisor];

    for(indx in arr) {

        if(isarray(arr[indx])) {

            for(sub_indx in arr[indx]) {

                if(sub_indx==curr_user) {

                    for(sub_indx2 in arr[curr_user])
                    arr[indx][sub_indx2]++;
                }
            }    
        }
    }
}

END {
    print h;

    for(i in arr) {

        if(isarray(arr[i])) {

            for(j in arr[i])
                printf "%-5s|%-11s|%-3s\n", i, j, id[i];
        }
    }
}

使用:

awk -f process_it.awk your_file.txt

相关内容