내 파일에는 사용자와 감독자 관계가 있는 다음 데이터가 있습니다.
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
각 사용자는 입력 파일("사용자" 열)에 한 번만 나타난다고 가정합니다. 또한 파이프( |
) 구분 기호가 실제로 파일에 있고 항상 공백으로 데이터와 구분되며 헤더 행은 다음과 같다고 가정합니다.아니요실제로 존재합니다.
이것이 사용된 2단계 솔루션입니다 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 '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
-사용자 ID관계형 배열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