У меня есть следующие данные в файле, который связан с отношениями пользователя и супервизора.
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?
Я предполагаю, что каждый пользователь во входном файле (в столбце «Пользователь» )только один раз. Далее я предполагаю, что вертикальная черта(|
)разделяет на самом деле находятся в файле, и что они всегда отделяются от данных пробелом, и что строка заголовка не на самом деле присутствует.
Вот двухпроходное -решение с использованием 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
; если вы этого хотите, укажите нужные правила форматирования.
Между прочим, эта операция широко известна как транзитивное замыкание .
Комплекс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) {... }
-пока супервизор находится в спискепользователей , получить родительский супервизор
Мое awk-решение (с использованием выходных форматов от Романа Перехреста ). По сути, есть две соответствующие петли. Во-первых, если для пользователя обрабатывается новый супервизор, то пользователю должны быть добавлены все зависимости этого супервизора (, т.е. цепочки супервизора -). После этого второй цикл ищет всех остальных пользователей, у которых в качестве зависимости есть текущий обрабатываемый пользователь, и к ним добавляются все зависимости текущего пользователя.:
#!/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