私のファイルには、ユーザーと監督者の関係を持つ次のデータがあります。
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
。最初のステップでは、各人の監督者を含む配列を作成し、2番目のステップでは出力を作成します。
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の出力形式を使用)デフォルトでは、2つの関連ループがあります。まず、ユーザーの新しいスーパーバイザーを操作する場合は、そのスーパーバイザーのすべての依存関係(つまり、スーパーバイザーチェーン)をそのユーザーに追加する必要があります。次に、2番目のループは、現在処理されているユーザーを依存関係として持つ他のすべてのユーザーを見つけ、現在のユーザーのすべての依存関係をここに追加します。
#!/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