|
現: 2020-12-26 (土) 16:08:10 yuji |
| + | * awk [#h57466c2] |
| + | awk(オーク)((開発者のAhoさん,Weinbergerさん,Kernighanさんの頭文字から名前付けられたらしい。))とは数値や文字列が規則正しく並んでいるテキストファイルに対して,以下の操作を行うのに適したコマンド(スクリプト言語)で,1977年から利用されている最古参のスクリプト言語。~ |
| + | - 編集(一部分の取り出し,並べ換え)~ |
| + | - 簡単な数値の計算(表計算)~ |
| + | 簡単な処理ならばC言語等でプログラムをするよりも,手早く行なうことができる。~ |
| | | |
| + | 文法はC言語に似ているんで,比較的覚えやすいかな。~ |
| + | |
| + | ** 簡単な使用 [#qb4c6f3a] |
| + | ''Hello world''を表示するプログラムは次のようになる。スクリプトファイルの拡張子は特に決まりがない。~ |
| + | ''hello.awk''~ |
| + | { print "Hello world!" } |
| + | |
| + | awkはgrepやsedのようなフィルタコマンドとして作られているので,何らかの入力が必要。~ |
| + | $ echo | awk -f hello.awk |
| + | |
| + | コマンドラインにプログラムを直接指定することもよく利用される。~ |
| + | $ echo | awk '{ print "Hello world!" }' |
| + | |
| + | ls -lの結果から所有者とグループとファイル名を表示する。~ |
| + | $ ls -l | awk '{ print $3, $4, $9 }' |
| + | yueno Administrator hello.awk |
| + | yueno Administrator sample.awk |
| + | |
| + | ファイル名がhello.awkだけ表示する。~ |
| + | $ ls -l | awk '$9=="hello.awk" { print $3, $4, $9 }' |
| + | yueno Administrator hello.awk |
| + | |
| + | /etc/passwdを'':''をデリミタとしてユーザ名とホームディレクトリのみを表示する。~ |
| + | $ cat /etc/passwd | awk -F: '{print $1, $6}' |
| + | yueno /home/ueno |
| + | |
| + | /etc/passwdのユーザ名とホームディレクトリを整形して表示する。~ |
| + | $ cat /etc/passwd | awk -F: '{printf("%-8s %s\n", $1, $6)}' |
| + | yueno /home/ueno |
| + | |
| + | df実行結果から2行目以降の第2カラムの合計を表示する |
| + | $ df | awk 'NR>=2 {z+=$2}; END {print z}' |
| + | 2850302964 |
| + | |
| + | |
| + | ** 実行方法 [#td5d6c32] |
| + | プログラムはコマンドラインに直接指定するか,''-f''オプションでプログラムファイル名を指定します。~ |
| + | 入力ファイルは標準入力または引数としてファイル名を渡す。~ |
| + | $ cat data.txt | awk '{ print $1, $2 }' # プログラムを直接指定 |
| + | $ cat data.txt | awk -f sample.awk # プログラムファイルで指定 |
| + | $ awk -f sample.awk data1.txt data2.txt # 入力データを引数で指定 |
| + | |
| + | bashを使っている場合,プログラムファイルの先頭を''#!/usr/bin/awk -f''とすると,プログラムファイルをコマンドとして直接実行することが出来る。~ |
| + | ''sample.awk''~ |
| + | #!/usr/bin/awk -f |
| + | { print $1, $8 } |
| + | |
| + | $ chmod 775 sample.awk |
| + | $ ./sample.awk |
| + | |
| + | ** レコードとフィールド [#j9e37ddc] |
| + | 入力データはレコードとフィールドに分割される。~ |
| + | レコードは行,フィールドは空白文字で区切られたカラムに相当する。レコードとフィールドの区切り文字は,ビルトイン変数''RS''と''FS''で変更することが出来る。~ |
| + | field1 field2 field3 # record1 |
| + | field1 field2 field3 # record2 |
| + | field1 field2 field3 # record3 |
| + | レコード全体は$0,フィールドは$1,$2,$3,...で参照出来る。~ |
| + | { print $0 } # レコード全体を表示 |
| + | { print $1, $2, $3 } # 1,2,3フィールドを表示 |
| + | |
| + | ** awkのプログラム [#d57e861b] |
| + | awkのプログラムは,「パターン-アクション規則」と「関数定義」でプログラムで記述する。~ |
| + | パターン{アクション} |
| + | パターン{アクション} |
| + | ... |
| + | function 名前(引数の並び){ 文 } |
| + | function 名前(引数の並び){ 文 } |
| + | ... |
| + | |
| + | awkは入力レコードを1行読むたびに,パターン-アクションを順に実行する。~ |
| + | パターンが真となるレコードに対して,対応するアクションが実行される。~ |
| + | パターンあるいは{アクション}のいずれかを省略することができる。~ |
| + | パターンを省略するとすべてのレコードにアクションが実行されて,{アクション}を省略するとパターンが真となるレコードを表示する。~ |
| + | |
| + | ** パターン [#i33a3d99] |
| + | パターンは次のどれかになる。 |
| + | BEGIN |
| + | END |
| + | 式 |
| + | /正規表現/ |
| + | パターン,パターン |
| + | |
| + | パターンには /.../ で正規表現を記述出来る。~ |
| + | /ABC/ { ... } # レコードの中にABCという文字列が含まれていればマッチ |
| + | |
| + | if (...) 文の ... に記述するような条件式を記述することもできる。~ |
| + | $1 == "ABC" { ... } # 第1フィールドがABCであればマッチ |
| + | |
| + | 条件式で正規表現を使用することもできる。''~''は正規表現にマッチしたらという演算子。~ |
| + | $1 ~ /^#/ { ... } # 第1フィールド先頭が#で始まっていたらマッチ |
| + | |
| + | 条件1,条件2を記述した場合,条件1が真になる行から,条件2が真になる行までマッチする。~ |
| + | $1=="START", $1=="END" { ... } # 1フィールドがSTARTである行から,ENDである行までマッチ |
| + | |
| + | BEGIN,ENDはプログラムの一番最初と一番最後にアクションを実行する。~ |
| + | BEGIN { ... } # 最初に1度だけアクションを実行 |
| + | END { ... } # 最後に1度だけアクションを実行 |
| + | |
| + | BEGINFILE,ENDFILEは各入力ファイルの開始時と終了時にアクションを実行する。~ |
| + | BEGINFILE { ... } # 最初に1度だけアクションを実行 |
| + | ENDFILE { ... } # 最後に1度だけアクションを実行 |
| + | |
| + | ** アクションと文 [#e509ae5c] |
| + | アクションは文の並び。~ |
| + | 文は次のいずれかになる。~ |
| + | 式 |
| + | 制御文 |
| + | 入出力文 |
| + | {文の並び} |
| + | 空文 |
| + | 文は,改行か'';''で区切る。'';''が単独で用いられると,空文を表す。~ |
| + | 文の前後には,空行を挿入してもよい。~ |
| + | |
| + | 長い文は,行末に''\''を置いて次行に続けることができる。~ |
| + | '', { && || do else''のあと,および''if( )'',''for( )''のあとは,''\''を置かずに改行しても継続とみなされる。~ |
| + | |
| + | アクションには,printで値を出力したり,if,whileなどで制御したり出来る。~ |
| + | { |
| + | if ($1 == "D") { # 1フィールドの値が"D"であれば |
| + | print $2, $3 # 2,3フィールドの値を出力する |
| + | } |
| + | } |
| + | |
| + | セミコロン(;)を使用すると、1行に複数の文を記述することができる。~ |
| + | { |
| + | a = 1; b = 2; c = 3; |
| + | print a, b, c |
| + | } |
| + | |
| + | ** 制御文 [#r5392a8f] |
| + | 制御文は次のいずれかである。~ |
| + | break |
| + | continue |
| + | do 文 while(式) |
| + | exit |
| + | exit(式) |
| + | if(式) 文 |
| + | if(式) 文 else 文 |
| + | for(式;式;式) 文 |
| + | for(変数 in 配列) 文 |
| + | next |
| + | return |
| + | return(式) |
| + | while(式) 文 |
| + | if-else文で最初の文がelseと同じ行にある場合,この文は'';''で終了するか''{ }''で囲まないとダメ。~ |
| + | |
| + | ** 基本的な制御構造 [#ofaa30c9] |
| + | |文の種類 |記法 |h |
| + | |逐次構造(文の並び) |{文1; 文2; ... 文n} | |
| + | |選択構造(if文) |if(式) 文 | |
| + | |選択構造(if-else文) |if(式) 文1 else 文2 | |
| + | |ループ構造(for文) |for(式1; 式2; 式3) 文| |
| + | |ループ構造(while文) |while(式) 文 | |
| + | |ループ構造(do-while文)|do 文 while(式) | |
| + | |
| + | ** 入出力文 [#x35c251a] |
| + | 入出力文は次のとおりである。 |
| + | getline 入力レコードを"$0"にセット |
| + | getline 式 0または1 |
| + | |
| + | |文の種類 |書式 |戻り値 |h |
| + | |比較 |式>=式 |0または1| |
| + | |~|式!=式 |0または1| |
| + | |~|式==式 |0または1| |
| + | |配列要素 |式 in 式 |0または1| |
| + | |パターンの検査 |式~/正規表現/ |0または1| |
| + | |~|式!~/正規表現/|0または1| |
| + | |和 |式+式 |演算結果| |
| + | |差 |式-式 |演算結果| |
| + | |積 |式*式 |演算結果| |
| + | |商 |式/式 |演算結果| |
| + | |剰余 |式%式 |演算結果| |
| + | |累乗 |式^式 |演算結果| |
| + | |文字列をつなげる|文字式 文字式|文字列 | |
| + | |
| + | ** 配列 [#kca2fea4] |
| + | 変数名[添え字]で配列を扱える。~ |
| + | foo[1] = 123 |
| + | foo[2] = "ABC" |
| + | print foo[1] # => 123 |
| + | print foo[2] # => ABC |
| + | |
| + | 添え字には文字列を使用することができる。~ |
| + | foo["name"] = "Ueno" |
| + | foo["age"] = 64 |
| + | print foo["name"] # => Ueno |
| + | print foo["age"] # => 64 |
| + | |
| + | 配列の個数はlength()で求められる。数値を添え字とする配列は次のようにしてループを回す。~ |
| + | foo[0] = "ABC" |
| + | foo[1] = "DEF" |
| + | for (i = 0; i < length(foo); i++) { |
| + | print foo[i] |
| + | } |
| + | |
| + | 添え字が文字列の場合は,次のようにしてループを回す。~ |
| + | foo["name"] = "Ueno" |
| + | foo["age"] = 64 |
| + | for (x in foo) { |
| + | print x "=" foo[x] # => name=Ueno, age=64 |
| + | } |
| + | |
| + | 配列の中に該当の要素があるかどうかを調べる場合。~ |
| + | foo["name"] = "Ueno" |
| + | if ("name" in foo) { |
| + | print "Exist" |
| + | } |
| + | |
| + | 配列要素を削除するには,deleteを使う。~ |
| + | foo["name"] = "Ueno" |
| + | foo["age"] = 64 |
| + | delete foo["name"] # foo["name"]を削除 |
| + | delete foo # 配列foo自体を削除 |
| + | |
| + | *** 多次元配列 [#r3c211e6] |
| + | 次のようにして多次元配列を扱うことができる。~ |
| + | foo[1, 1] = 1001 |
| + | foo[1, 2] = 1002 |
| + | foo[2, 1] = 2001 |
| + | foo[2, 2] = 2002 |
| + | for (i = 1; i <= 2; i++) { |
| + | for (j = 1; j <= 2; j++) { |
| + | print foo[i, j] |
| + | } |
| + | } |
| + | |
| + | 配列の配列の場合も可能。~ |
| + | foo[1][1] = 1001 |
| + | foo[1][2] = 1002 |
| + | foo[2][1] = 2001 |
| + | foo[2][2] = 2002 |
| + | for (i in foo) { |
| + | for (j in foo[i]) { |
| + | print foo[i][j] |
| + | } |
| + | } |
| + | |
| + | ** print文 [#q4aa79af] |
| + | printは,変数や値を出力する。~ |
| + | print $1, $2, $3 |
| + | |
| + | 値をカンマ'',''で連結すると,ビルトイン変数''OFS''に指定された出力フィールドセパレータ(デフォルトは半角スペース)で区切って出力する。~ |
| + | a = "AA"; b = "BB"; c = "CC"; |
| + | print a, b, c # => AA BB CC |
| + | |
| + | ''OFS''を変更することで,区切り文字を変更することが出来る。~ |
| + | a = "AA"; b = "BB"; c = "CC"; |
| + | OFS = "," |
| + | print a, b, c # => AA,BB,CC |
| + | |
| + | 値をカンマ'',''で区切らない場合は,文字列の連結が行われた後に出力される。~ |
| + | a = "AA"; b = "BB"; c = "CC"; |
| + | print a b c # => AABBCC |
| + | |
| + | ** 組み込み変数 [#c46f3b0e] |
| + | 次のような組み込み変数が用意されている。 |
| + | |組み込み変数 |値 |h |
| + | |ARGC |コマンド行の引数の数 | |
| + | |ARGV |コマンド行の引数の配列 | |
| + | |FILENAME |現在の入力ファイル名 | |
| + | |ENVIRON["..."]|環境変数の値 | |
| + | |FS |入力のフィールドセパレータ(はじめはスペースまたはタブ)| |
| + | |RS |入力のレコードセパレータ(はじめは改行) | |
| + | |NF |現在レコードのフィールド数 | |
| + | |NR |現在の通算レコード | |
| + | |FNR |現在の入力ファイルの通算レコード | |
| + | |OFS |表示のフィールドセパレータ(はじめはスペース) | |
| + | |ORS |表示のレコードセパレータ(はじめは改行) | |
| + | |OFMT |数の表示のフォーマット(はじめは"%.6g") | |
| + | |RSTART |matchでマッチした文字列の開始位置 | |
| + | |RLENGTH |matchでマッチした文字列の長さ | |
| + | |$0 |現在の入力レコード | |
| + | |$1,...,$NF |第1フィールド,...,第NFフィールド | |
| + | |
| + | ** 組み込み文字列関数 [#dc54de92] |
| + | |組み込み文字列変数|値 |h |
| + | |gsub(r,s,t) |文字列tの中に現れる文字列rをすべて文字列sで置換する。置換した数を返す。tを省略すると$0が使われる。| |
| + | |index(s,t) |文字列sの中の文字列tの位置を返す。tが現れない場合は0 | |
| + | |jindex(s,t) |日本語文字列sの中の文字列tの位置を返す。tが現れない場合は0。 | |
| + | |length(s) |文字列sの長さを返す。 | |
| + | |jlength(s) |日本語文字列sの長さを返す。 | |
| + | |match(s,r) |文字列sが文字列rにマッチする位置を返す。マッチしないときは0。 | |
| + | |split(s,a,fs) |fsをフィールドセパレータとして文字列sを配列aに分解し,フィールド数を返す。 | |
| + | |sprintf(書式,式) |書式で整えた式の並びを返す。 | |
| + | |sub(r,s,t) |gsub()と同様。ただしはじめの1回だけ置換する。 | |
| + | |substr(s,i,n) |文字列sのi番目から始まるn文字を返す。 | |
| + | |jsubstr(s,i,n) |日本語文字列sのi番目から始まるn文字を返す。 | |
| + | |
| + | ** 組み込み算術関数 [#mbdeebbb] |
| + | |組み込み算術変数|値 |h |
| + | |atan2(y,x) |atan(y/x)で-π~πの値| |
| + | |sin(x) |sin関数 | |
| + | |cos(x) |cos関数 | |
| + | |exp(x) |exp関数 | |
| + | |log(x) |自然対数 | |
| + | |sqrt(x) |平方根 | |
| + | |int(x) |小数点以下を切り捨て | |
| + | |rand() |疑似乱数 0以上1未満| |
| + | |srand() |乱数の初期化 | |
| + | |
| + | ** 書式変換 [#r42c248e] |
| + | printfとsprintfの中では次のような変換が利用できる。~ |
| + | |記法 |値 |h |
| + | |printf("|%c|",65) |A | |
| + | |printf("|%d|",65) |65 | |
| + | |printf("|%5d|",65) | 65 | |
| + | |printf("|%05d|",65) |00065 | |
| + | |printf("|%f|",65) |65.000000 | |
| + | |printf("|%5.1f|",65) | 65.0 | |
| + | |printf("|%e|",65) |6.500000e+01| |
| + | |printf("|%5.1e|",65) |6.5e+01 | |
| + | |printf("|%g|",65) |65 | |
| + | |printf("|%o|",65) |101 | |
| + | |printf("|%s|","yuji") |yuji | |
| + | |printf("|%10s|","yuji") | yuji | |
| + | |printf("|%-10s|","yuji") |yuji | |
| + | |printf("|%.4s|","yujiueno") |yuji | |
| + | |printf("|%10.4s|","yujiueno")| yuji | |
| + | |printf("|%-10.4s|","yuji") |yuji | |
| + | |printf("|%%|") |% | |
| + | |
| + | ** 正規表現 [#e4f5af49] |
| + | 正規表現の記法を示す。~ |
| + | |記法 |値 |h |
| + | |A |Aそのもの(以下の特殊文字を除く普通の文字)| |
| + | |\\ |\そのもの | |
| + | |\" |"そのもの | |
| + | |\t |タブ | |
| + | |\n |改行 | |
| + | |\f |フォームフィード | |
| + | |\b |バックスペース | |
| + | |\033 |8進数033 | |
| + | |^a |文字列の先頭が'a' | |
| + | |a$ |文字列の末尾が'a' | |
| + | |. |任意の1文字 | |
| + | |[abc] |'a''b''c'のどれか1文字 | |
| + | |[^abc] |'a''b''c'以外の1文字 | |
| + | |[a-e] |'a''b''c''d''e'のどれか1文字 | |
| + | |[^a-e] |'a''b''c''d''e'以外の1文字 | |
| + | |a* |0個以上の'a'の並び | |
| + | |a+ |1個以上の'a'の並び | |
| + | |a? |'a'が1個あるいは0個 | |
| + | |abc|de|"abc"または"de" | |