次のファイルがあるとしましょう。
Thu May 8 15:32:07 2014
User-Name = "Mark"
Framed-IP-Address = 0.0.0.0
Acct-Status-Type = Interim-Update
Acct-Input-Octets = 95684
Acct-Output-Octets = 23564
Thu May 8 15:32:07 2014
User-Name = "Mike"
Framed-IP-Address = 0.0.0.0
Acct-Status-Type = Interim-Update
Acct-Input-Octets = 95684
Acct-Output-Octets = 23564
Thu May 8 15:32:07 2014
User-Name = "Mike"
Framed-IP-Address = 0.0.0.0
Acct-Status-Type = Interim-Update
Acct-Input-Octets = 95684
Acct-Output-Octets = 23564
Thu May 8 15:32:07 2014
User-Name = "Mark"
Framed-IP-Address = 0.0.0.0
Acct-Status-Type = Interim-Update
Acct-Input-Octets = 95684
Acct-Output-Octets = 23564
grep
withオプションを使用してユーザーに関する情報を取得しました-A
。
grep -A4 "Mark" test
User-Name = "Mark"
Framed-IP-Address = 0.0.0.0
Acct-Status-Type = Interim-Update
Acct-Input-Octets = 95684
Acct-Output-Octets = 23564
--
User-Name = "Mark"
Framed-IP-Address = 0.0.0.0
Acct-Status-Type = Interim-Update
Acct-Input-Octets = 95684
Acct-Output-Octets = 23564
しかし、私が望む結果は次のとおりです。
User-Name = "Mark"
Acct-Input-Octets = 95684 95684
Acct-Output-Octets = 23564 23564
Framed-IP-Address = 0.0.0.0
私たちが知っているように、「Mark」の後の最初の2行を削除し、Acct-Status-Type = Interim-Update
同じフィールドのすべての値を同じ行に配置したいですか?
〜のようにウォーリック提案、私の質問の最初の部分は簡単に答えることができます。
grep -A4 "Mark" test| grep -v Framed-IP-Address | grep -v Acct-Status-Type
これは一例であり、ファイルにはユーザー名= "Mark"を含む多くのセクションを含めることができ、必要な出力は次のようになります。
User-Name = "Mark"
Acct-Input-Octets = val1 val2 val3 val4 .......
Acct-Output-Octets = val1 val2 val3 val4 ........
答え1
search.awk
BEGIN {
FS = "="
cur_username = ""
}
$1 ~ /User-Name/ {
cur_username = $2
gsub(/^[ \t]+/, "", cur_username)
gsub(/[ \t]+$/, "", cur_username)
}
$1 !~ /User-Name/ {
if ((NF != 2) || (cur_username != searched_user))
next
key = $1
gsub(/^[ \t]+/, "", key)
gsub(/[ \t]+$/, "", key)
value = $2
gsub(/^[ \t]+/, "", value)
gsub(/[ \t]+$/, "", value)
values[key] = values[key] " " value
}
END {
printf("User-Name = %s\n", searched_user)
for(key in values) {
printf("\t%s =%s\n", key, values[key])
}
}
テスト実行:
$ awk -f search.awk -v 'searched_user="Mark"' input
User-Name = "Mark"
Acct-Status-Type = Interim-Update Interim-Update
Acct-Input-Octets = 95684 95684
Framed-IP-Address = 0.0.0.0 0.0.0.0
Acct-Output-Octets = 23564 23564
ボーナス -group.awk
すべてのレコードをグループ化する場合(残念です。ノックいいえasorti
):
BEGIN {
FS = "="
cur_username = ""
}
$1 ~ /User-Name/ {
cur_username = $2
gsub(/^[ \t]+/, "", cur_username)
gsub(/[ \t]+$/, "", cur_username)
}
$1 !~ /User-Name/ {
if (NF != 2)
next
key = $1
gsub(/^[ \t]+/, "", key)
gsub(/[ \t]+$/, "", key)
value = $2
gsub(/^[ \t]+/, "", value)
gsub(/[ \t]+$/, "", value)
users[cur_username,key] = users[cur_username,key] " " value
}
END {
n = asorti(users, sorted)
prev_username = ""
for (i=1; i<=n; i++) {
username_key = sorted[i]
split(username_key, a, SUBSEP)
username = a[1]
key = a[2]
value = users[sorted[i]]
if (username != prev_username) {
printf("User-Name = %s\n", username)
prev_username = username
}
printf("\t%s =%s\n", key, value)
}
}
テスト実行:
$ gawk -f group.awk input
User-Name = "Mark"
Acct-Input-Octets = 95684 95684
...
User-Name = "Mike"
Acct-Input-Octets = 95684 95684
...
答え2
次のようなことができます
awk -vRS= -F'\n' '$2 ~ /Mark/ {
vals["User-Name"] = "Mark"
for (i=5;i<=NF;i++) {
split($i,a," = ");
vals[a[1]]=sprintf("%s %s", vals[a[1]], a[2]);
}
}
END{for (i in vals) print i,"=",vals[i];}' test
test
あなたのファイルについてそれを提供します
User-Name = Mark
Acct-Input-Octets = 95684 95684
Acct-Output-Octets = 23564 23564
答え3
- このユーザーに関するデータを収集するには、必要な段落をフィルタリングしてください。
- 必須キー(
Acct-Input-Octets
およびAcct-Output-Octets
)を含む行をフィルタリングします。間隔が一貫していない場合は、このステップで間隔を標準化する必要があります。 - キーで項目を並べ替えます(値の順序に興味がない場合は、安定した並べ替えを使用してください)。
- 同じキーの順序を縮小します。
awk -v RS= '/User-Name = "Mark"/' |
grep -E 'Acct-(Input|Output)-Octets *=' |
sort -k1,1 -s |
awk '
BEGIN {printf "User-Name = \"Mark\""}
$1 == key { printf " %s", $3; }
$1 != key { key = $1; printf "\n%s", $0; }
END { print "" }'