ドットインストールの学習メモです
始める前に、VM(VirtualBox)上のフォルダをvscodeでどうやって開こうかと、
苦心惨憺していたが、そういえば、とcyberduckを思い出してやってみたら
早い早い。一瞬で開いた。
今までなんでサイバーダダックがあるのかわかんなかったが
ターミナルだけで開こうとすると、VMにsshトンネル?を繋いでヤンなきゃいけないので
大変そうだった。というかめんどくさそうな割に成果に見合わないと直感的に思った。
作業しててもこれ以上進めてはいけない、と感じたし。
というわけで、テンキュー、ダック。
##はじめてのawkプログラム
- myapp.awkを作成
{
print $4
}
scores.datの内容
2017-06-18 03:51:28 tanaka 181 294 49 278
2017-06-18 08:29:58 taguchi 183 206 10 1
2017-06-18 09:30:18 fkoji 160 198 114 324
2017-06-18 14:47:22 fkoji 273 442 31 274
2017-06-19 02:23:08 fkoji 252 270 416 240
.
.
.
ターミナルで実行
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
すると
181
183
160
273
252
.
.
.
とscores.datの4列目の内容が改行つきで出力される。
短い命令なので、全部ひとまとめに・・・
[vagrant@localhost awk_lessons]$ awk '{print $4}' scores.dat
でもおk。
##フィールドの指定
{
print $3,$4
#3列目と4列目を表示
print $3 ":" $4
#間に”でコロンを表示
print $0
#全てのフィールドを表示
print NF, $NF
#number of fieldsでレコードに含まれるフィールドの数
#$NFで最後のフィールドを意味する
print NR ":" $0
#number of recordsで何番目のレコードかを表す。
#上の場合全てのフィールドを行番号つきで表してくれる
}
##レコードの指定
レコード番号3以下を表示
NR < 3{ ←(パターンと呼ぶ)
print NR ":" $0 ←(アクションと呼ぶ)
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
1:2017-06-18 03:51:28 tanaka 181 294 49 278
2:2017-06-18 08:29:58 taguchi 183 206 10 1
<taguchiと$4あ100より大きい物を抽出>
($3 == "taguchi") && ($4 > 100) {
print $3,$4
}
<$3がtから始まる物を全て抽出>
$3 ~ /^t.*/ {
print $0
}
##BEGIN,ENDを使ってみよう
BEGIN { #最初のみ実行
print "--- START ---"
}
NR > 5 && NR < 10 {
print $0
}
END { #最後のみ実行
print "--- END ---"
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
--- START ---
2017-06-19 12:44:08 tanaka 195 297 102 102
2017-06-19 13:04:43 fkoji 356 399 277 218
2017-06-20 01:53:41 tanaka 399 67 275 290
2017-06-20 06:14:21 taguchi 213 404 333 199
--- END ---
###FS=Field Separater (通常は空白。区切り文字を変える)
BEGIN {
FS = "-"
}
NR > 5 && NR < 10 {
print $1,$2
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
2017 06
2017 06
2017 06
2017 06
2017-06-19 12:44:08 tanaka 195 297 102 102
2017-06-19 13:04:43 fkoji 356 399 277 218
2017-06-20 01:53:41 tanaka 399 67 275 290
2017-06-20 06:14:21 taguchi 213 404 333 199
の - の部分でセパレートして、一番目と二番目を表示した。
RS = Record Separater (通常は改行。レコードの終わりを変える)
NR == 1{
print $0
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
2017-06-18 03:51:28 tanaka 181 294 49 278
だったものが
BEGIN {
RS = ":"
}
NR == 1{
print $0
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
2017-06-18 03
となる。
03の後の:で終わりと認識された、ということ。
###OFSとORS
- Output Field Separater
- Output Record Separater
BEGIN {
OFS = "@"
ORS = "|"
}
NR > 5 && NR < 10 {
print $3, $4
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
tanaka@195|fkoji@356|tanaka@399|taguchi@213|[vagrant@localhost awk_lessons]$
$3と$4のフィールドの変わり目に @ が、
レコードの変わり目に | が入っていることがわかる。
##変数と演算子
BEGIN {
total = 0
}
NR < 4 {
total += $4
}
END {
print total
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
524
##printfによる出力
書式を指定して出力できる
NR > 96 {
1. $3名前、$4~7の合計、$4〜7の平均を表す
print $3, ($4+$5+$6+$7), (($4+$5+$6+$7)/4)
2. それぞれに項目の名前を表示する
printf "Name: %s Sum: %d Avg: %f\n", $3,
($4+$5+$6+$7), (($4+$5+$6+$7)/4)
3. それぞれ10桁(Avgは小数点2桁も+)にする。Nameは-を足して左揃えにする。
printf "Name: %-10s Sum: %10d Avg: %010.2f\n", $3,
($4+$5+$6+$7), (($4+$5+$6+$7)/4)
4.Sumに3桁ごとに,を入れる。%の後に’を入れる。
printf "Name: %-10s Sum: %'10d Avg: %010.2f\n", $3,
($4+$5+$6+$7), (($4+$5+$6+$7)/4)
}
1.
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
fkoji 1027 256.75
taguchi 1272 318
fkoji 1025 256.25
2.
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: fkoji Sum: 1027 Avg: 256.750000
Name: taguchi Sum: 1272 Avg: 318.000000
Name: fkoji Sum: 1025 Avg: 256.250000
3.
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: fkoji Sum: 1027 Avg: 0000256.75
Name: taguchi Sum: 1272 Avg: 0000318.00
Name: fkoji Sum: 1025 Avg: 0000256.25
4.
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: fkoji Sum: 1,027 Avg: 0000256.75
Name: taguchi Sum: 1,272 Avg: 0000318.00
Name: fkoji Sum: 1,025 Avg: 0000256.25
##組み関数を使う
awkで既に用意されてる便利な命令。
BEGIN {
print int(3.8) #3が出力
print length("hello") #5
print substr("hello", 3) #llo
print substr("hello", 3, 2) #ll
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
3
5
llo
ll
##ifによる条件分岐
NR < 15 {
print NR ":" $0
if (NR % 10 == 0) {
print "------"
} else if (NR % 5 == 0) {
print "---"
} else {
print "-"
}
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
1:2017-06-18 03:51:28 tanaka 181 294 49 278
-
2:2017-06-18 08:29:58 taguchi 183 206 10 1
-
3:2017-06-18 09:30:18 fkoji 160 198 114 324
-
4:2017-06-18 14:47:22 fkoji 273 442 31 274
-
5:2017-06-19 02:23:08 fkoji 252 270 416 240
---
6:2017-06-19 12:44:08 tanaka 195 297 102 102
-
7:2017-06-19 13:04:43 fkoji 356 399 277 218
-
8:2017-06-20 01:53:41 tanaka 399 67 275 290
-
9:2017-06-20 06:14:21 taguchi 213 404 333 199
-
10:2017-06-20 08:17:19 fkoji 23 350 204 463
------
11:2017-06-20 17:04:52 fkoji 380 155 232 412
-
12:2017-06-21 00:07:26 tanaka 31 387 54 236
-
13:2017-06-21 12:38:52 tanaka 452 469 5 165
-
14:2017-06-22 01:50:47 tanaka 300 478 168 440
-
15:2017-06-22 13:17:56 tanaka 186 464 381 133
---
##whileでの繰り返し
NR < 4 {
sum = 0
i = 4
while (i <= 7) {
sum += $i
i++
}
printf "Name: %-10s Sum: %'10d\n", $3, sum
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: tanaka Sum: 802
Name: taguchi Sum: 400
Name: fkoji Sum: 796
##for,continue,break
for 繰り返し文
continue 条件に合ったものをスキップする(無視する)。
break 条件に合ったものがあったらそこで終了する。
NR < 4 {
sum = 0
for (i = 4; i <= 7; i++){
if ($i < 100){
# continue
break
}
sum += $i
}
printf "Name: %-10s Sum: %'10d\n", $3, sum
}
forのみ
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: tanaka Sum: 802
Name: taguchi Sum: 400
Name: fkoji Sum: 796
continue 100未満は無視
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: tanaka Sum: 753
Name: taguchi Sum: 389
Name: fkoji Sum: 796
break 100未満が出てきたろそこで終了
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: tanaka Sum: 475
Name: taguchi Sum: 389
Name: fkoji Sum: 796
##配列を使う
BEGIN {
# rank1 = "Gorld"
# rank2 = "Silver"
# rank3 = "Bronz"
# rank[1] = "Gorld"
# rank[2] = "Silver"
# rank[3] = "Bronz"
split("Gorld Silver Bronz", ranks)
print ranks[1] #Gorld
ranks[2] = "Plata"
print ranks[2] #Plata
exit
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Gorld
Plata
##配列をforで処理
lengthを配列に対して使うと要素数を返してくれる。
BEGIN {
split("Gorld Silver Bronz", ranks)
print "Available Ranks"
# for (i = 1; i <= 3; i++) {
for (i = 1; i <= length(ranks); i++) {
print ranks[i]
}
print "------"
}
NR < 4 {
sum = 0
for (i = 4; i <= 7; i++){
if ($i < 100){
# continue
# break
}
sum += $i
}
if (sum > 1000) {
rank = ranks[1]
} else if (sum > 800) {
rank = ranks[2]
} else {
rank = ranks[3]
}
printf "Name: %-10s Sum: %'10d Rank: %-10s\n", $3, sum, rank
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Available Ranks
Gorld
Silver
Bronz
------
Name: tanaka Sum: 802 Rank: Silver
Name: taguchi Sum: 400 Rank: Bronz
Name: fkoji Sum: 796 Rank: Bronz
##関数を自分で作ってみよう
NR < 4 {
sum = getSum()
rank = getRank(sum)
printf "Name: %-10s Sum: %'10d Rank: %-10s\n", $3, sum, rank
}
function getSum() {
sum = 0
for (i = 4; i <= 7; i++){
sum += $i
}
return sum
}
function getRank(sum) {
split("Gorld Silver Bronz", ranks)
if (sum > 1000) {
rank = ranks[1]
} else if (sum > 800) {
rank = ranks[2]
} else {
rank = ranks[3]
}
return rank
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: tanaka Sum: 802 Rank: Silver
Name: taguchi Sum: 400 Rank: Bronz
Name: fkoji Sum: 796 Rank: Bronz
##連想配列を使う
rank[1]などの添字に文字列などを使った配列を連想配列と呼ぶ。
NR < 4 {
sum = getSum()
rank = getRank(sum)
printf "Name: %-10s Sum: %'10d Rank: %-10s\n", $3, sum, rank
}
function getSum() {
sum = 0
for (i = 4; i <= 7; i++) {
sum += $i
}
return sum
}
function getRank(sum) {
# split("Gold Silver Bronze", ranks)
ranks["first"] = "Gold"
ranks["second"] = "Silver"
ranks["third"] = "Bronze"
if (sum > 1000) {
rank = ranks["first"]
} else if (sum > 800) {
rank = ranks["second"]
} else {
rank = ranks["third"]
}
return rank
}
###連想配列は集計に便利な場面も。
ユーザーごとに全てのスコアの合計を求める。
{
sum = getSum()
total[$3] += sum
# total[taguchi...] += sum などの意
}
END {
for (name in total) {
#totalから1つずつ添え字を取り出してnameへ
printf "Name: %-10s Todal: %'10d\n",name, total[name]
}
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: fkoji Todal: 38,844
Name: taguchi Todal: 31,756
Name: tanaka Todal: 28,185
[vagrant@localhost awk_lessons]$
##グラフを書く
{
sum = getSum()
total[$3] += sum
}
END {
for (name in total) {
printf "Name: %-10s Total: %'10d %s\n", name, total[name], getBarGraph(total[name])
}
}
function getBarGraph(total) {
s = ""
for (i = 1; i <= int(total / 1000); i++) {
s = s "*"
}
return s
}
function getSum() {
sum = 0
for (i = 4; i <= 7; i++) {
sum += $i
}
return sum
}
function getRank(sum) {
# split("Gold Silver Bronze", ranks)
ranks["first"] = "Gold"
ranks["second"] = "Silver"
ranks["third"] = "Bronze"
if (sum > 1000) {
rank = ranks["first"]
} else if (sum > 800) {
rank = ranks["second"]
} else {
rank = ranks["third"]
}
return rank
}
[vagrant@localhost awk_lessons]$ awk -f myapp.awk scores.dat
Name: fkoji Total: 38,844 **************************************
Name: taguchi Total: 31,756 *******************************
Name: tanaka Total: 28,185 ****************************