awk プログラミング#
awk 演算子#
算術演算子#
演算子 | 説明 |
---|
+ - * / % | 足し算 引き算 掛け算 割り算 余り |
^ ** | 累乗 |
++ -- | インクリメント デクリメント (前置または後置として使用可能) |
代入演算子#
演算子 | 説明 |
---|
= += -= *= /= %= ^= **= | 代入文(a+=b は a=a+b と等価、他も同様) |
関係演算子#
演算子 | 説明 |
---|
> < >= <= != == | 比較文(成立時は真を返し、成立しない時は偽を返す) |
論理演算子#
演算子 | 説明 |
---|
|| | 論理和(真があれば真) |
&& | 論理積(偽があれば偽) |
! | 論理否定(真は偽に、偽は真に) |
正規表現演算子#
演算子 | 説明 |
---|
~ | 正規表現にマッチ |
!~ | 正規表現にマッチしない |
その他の演算子#
演算子 | 説明 |
---|
$ | フィールド参照 |
空白 | 文字列結合子 |
in | 配列メンバーの反復子(通常は for ループと共に使用し、配列を走査するため) |
? : | 三項演算子(C 言語と同様: 式 ? 文1 : 文2 式が成立すれば文 1 を実行し、そうでなければ文 2 を実行) |
awk フロー制御文#
条件判断文#
# if
if(式)
文
# if-else
if(式)
文1
else
文2
# if-else-if
if(式)
文1
else if (式2)
文2
else
文3
awk の分岐構造はネストを許可しており、判断と読みやすさを向上させるために、複数の文を {} で括ることができます。
ループ文#
# whileループ
while(式){
文
}
# forループ
# フォーマット1
for(初期変数;ループ判断文;ループ反復増加/減少文){
文
}
# フォーマット2
for(変数 in 配列){
文
}
# do-whileループ
do{
文
} while(条件)
ループフローを変更する文:
break;
ループを終了
continue;
今回のループをスキップ
exit status_code;
exit
文はスクリプトの実行を停止するために使用されます(END
があれば END
に移行)、整数パラメータを受け取り、awk
プロセスの終了ステータスコードとして使用されます。パラメータが提供されない場合、デフォルトは 0 です( $?
で確認できます)。
awk 配列#
配列は awk の魂であり、テキスト処理では配列処理がよく使用されます。
awk
配列の特性:
awk
配列のインデックスは数字でも文字列でも可能であるため、awk
の配列は連想配列です。
- 内部的に、
awk
配列のインデックスはすべて文字列であり、数値インデックスも使用時に内部で文字列に変換されます。
awk
の配列要素の順序は、要素挿入時の順序と必ずしも一致しません。
awk
の配列は事前に宣言する必要はなく、サイズを宣言する必要もありません。
- 配列要素は文脈に応じて 0 または空文字列で初期化されます。
配列の作成(追加、変更)#
構文:配列名[インデックス] = 値
- 配列に要素を追加 / 変更する構文は、配列を作成するのと同じです。
配列要素へのアクセス#
構文:配列名[インデックス]
配列要素の削除#
構文:delete 配列名[インデックス]
- 存在しない要素を削除してもエラーは発生しません。
delete 配列名
は配列のすべての要素を直接削除できます。
配列関連関数#
-
length(arr)
配列の長さを取得
-
asort(arr)
配列をソートし、配列の長さを返す
-
split(str,arr,sep)
文字列を配列に分割し、配列の長さを返す
生成された awk 配列のインデックスは 1 から始まり、C 言語の配列とは異なります。
[root@localhost ~]# awk 'BEGIN{str="a,b,c,d";len=split(str,arr,",");print len,length(arr),asort(arr),arr[1]}'
4 4 4 a
配列の反復#
# 方法1
[root@localhost ~]# awk 'BEGIN{
str="a,b,c,d";
len=split(str,arr,",");
for(i in arr){
print i,arr[i];
}
}'
1 a
2 b
3 c
4 d
# 方法2 (awk配列は連想配列であり、この方法は順序付きの反復を保証します)
[root@localhost ~]# awk 'BEGIN{
str="a,b,c,d";
len=split(str,arr,",");
for(i=1;i<=len;i++){
print i,arr[i];
}
}'
1 a
2 b
3 c
4 d
# 配列に特定のキーが含まれているかどうかを判断
if(key in arr)
# arrが配列かどうかを検出
isarray(arr) arrが配列であれば1を返し、そうでなければ0を返す
typeof(arr) データ型を返し、arrが配列であれば 'array' を返す
多次元配列#
- awk は一次元配列のみをサポートしており、一次元配列を使用して多次元配列をシミュレートできます。
# 次のような3*3の二次元配列arr:
1 2 3
4 5 6
7 8 9
C言語では、arr[0][0] = 100;awkでは、arr[0,0] = 100と設定できます。これにより、arr[0,1]、arr[0,2]...arr[3,3]となります。
実際には、0,1 0,2 3,3 は単なる文字列インデックスです。
awk 組み込み関数#
数学関数#
関数 | 説明 |
---|
sin(expr) | expr の正弦値を返す |
cos(expr) | expr の余弦値を返す |
atan2(y,x) | y/x の逆正接値を返す |
log(expr) | expr の自然対数を返す |
exp(expr) | 底 e の expr の指数値を返す |
sqrt(expr) | expr の平方根を返す |
int(expr) | expr を整数に切り捨てた値を返す |
rand() | 任意の数字 n を返す、0<=n<1 |
srand([expr]) | rand 関数のシード値を expr パラメータの値に設定します。パラメータを省略すると、ある日の時間を使用します。 |
# 0-99の間のランダム整数を取得
[root@localhost ~]# awk 'BEGIN{srand();randint=int(100*rand());print randint}'
文字列関数#
関数 | 説明 |
---|
asort(arr [, d ]) | ASCII 文字順に配列 arr の値をソート |
asorti(arr [, d]) | ASCII 文字順に配列 arr のキーをソート |
gsub(regexp, sub, str) | 文字列内で指定されたパターンにマッチするすべての文字列を検索し、見つかったものを別の文字列に置き換える |
sub(search, sub, str) | 文字列内で指定された文字列を検索し、見つかった場合は別の文字列に置き換える。1 回だけ置き換えます |
index(str, sub) | ある文字列が別の文字列内にある位置を検索します。見つかればその位置を返し、見つからなければ 0 を返します |
length(str) | 文字列の長さを返す |
match(str, regexp) | マッチするパターンの最初の最長部分文字列の位置を検索します。見つからなければ 0 を返し、見つかれば最長部分文字列の開始位置を返します |
split(str, arr, regexp) | 文字列を指定されたパターンに基づいて複数の部分文字列に分割します。パターンを渡さない場合は、変数 FS の値を使用します |
printf(format, expr-list) | 指定された文字列フォーマットと渡された変数に基づいて文字列を構築し、標準出力に出力します |
strtonum(str) | 文字列が数字かどうかをチェックし、それを 10 進数に変換します |
substr(str, start, len) | 文字列 str の start の位置から始まり、長さが len の部分文字列を返します |
tolower(str) | 指定された文字列内の大文字を小文字に変換します |
toupper(str) | 指定された文字列内の小文字を大文字に変換します |
# asort(arr[,d]) arr-->配列 d-->配列。もしこのパラメータを渡すと、arrは変更されず、arrのすべての要素がdにコピーされ、dがソートされます。
[root@localhost ~]# awk 'BEGIN{
arr[11]=800;
arr[22]=200;
arr[33]=300;
arr[44]=100;
for(i in arr){
print i,arr[i];
}
asort(arr);
print;
for(j in arr){
print j,arr[j];
}
}'
11 800
22 200
33 300
44 100
1 100
2 200
3 300
4 800
# asorti
[root@localhost ~]# awk 'BEGIN{
arr[11]=800;
arr[22]=200;
arr[33]=300;
arr[44]=100;
for(i in arr){
print i,arr[i];
}
asorti(arr);
print;
for(j in arr){
print j,arr[j];
}
}'
11 800
22 200
33 300
44 100
1 11
2 22
3 33
4 44
# gsub(regexp, sub, str)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
gsub("[o|l]","*",str);
print str;
}'
he*** w*r*d
# sub(search, sub, str)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
sub("[o|l]","*",str);
print str;
}'
he*lo world
# index(str, sub)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
idx=index(str,"l");
print idx;
}'
3
# match(str, regexp)
[root@localhost ~]# awk 'BEGIN{
str="hello world hi haaaaaa";
idx=match(str,"h*");
print idx;
}'
1
# strtonum(str)
[root@localhost ~]# awk 'BEGIN{
str="01010";
res=strtonum(str);
print res;
}'
520
# substr(str, start, len)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
res=substr(str,7,5);
print res;
}'
world
# tolower(str)
[root@localhost ~]# awk 'BEGIN{
str="HAHAHA";
res=tolower(str);
print res;
}'
hahaha
# tolupper(str)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
res=toupper(str);
print res;
}'
HELLO WORLD
日付と時間の関数#
関数 | 説明 |
---|
systime() | 現在のタイムスタンプを返す |
mktime(datespec) | 指定された形式の時間文字列(YYYY MM DD HH MM SS )をタイムスタンプに変換します |
strftime([format [, timestamp]]) | タイムスタンプ形式の時間を指定された時間フォーマットに基づいて文字列形式で表現します |
# systime()
[root@localhost ~]# awk 'BEGIN{print systime()}'
1672448348
# mktime(datespec)
[root@localhost ~]# awk 'BEGIN{print mktime("2022 12 31 09 00 00")}'
1672448400
# strftime([format [, timestamp]])
[root@localhost ~]# awk 'BEGIN{print strftime("%c",systime())}'
Sat Dec 31 09:03:53 2022
フォーマット#
フォーマット記号 | 説明 |
---|
%a | ローカライズされた曜日、例えば 木曜日 |
%A | ローカライズされた曜日の略称、例えば 木 |
%b | ローカライズされた月の名前、例えば 5月 |
%B | ローカライズされた月、例えば 5月 |
%c | C 言語の %A %B %d %T %Y の形式、例えば 2019年05月30日 木曜日 21時08分37秒 |
%C | 本年度の世紀部分。つまり、4 桁の年の最初の 2 桁、例えば 2019 年の 20 |
%d | 当月の何日か、範囲は 01-31 、例えば 30 |
%D | フォーマット %m/%d/%y の略称、例えば 05/30/19 |
%e | 当月の何日か、範囲は 1-31 、10 未満の場合は前に空白を補う、例えば 1 は 1 に補完 |
%F | ISO 8601 日付形式の %Y-%m-%d の別名 |
%g | ISO 8601 日付形式の週番号を 100 で割った値、範囲 00-99 例えば 1993 年 1 月 1 日は 1992 年の第 53 週 |
%G | ISO 週番号制の完全な年、4 桁の年のように、例えば 2019 |
%h | フォーマット %b の別名 |
%H | 24 時間制の現在の時間の時、範囲は 00–23 |
%I | 12 時間制の現在の時間の時、範囲は 01–12 |
%j | 一年の何日か、範囲は 001–366 |
%m | 現在の時間の月、範囲は 01–12 |
%M | 現在の時間の分、範囲は 00–59 |
%n | 改行文字 \n |
%p | ローカライズされた 12 時間制の時間形式の AM または PM 、つまりローカライズされた午前または午後の表現 |
%r | ローカライズされた 12 時間制の時間形式、C 言語の %I:%M:%S %p に似ています |
%R | フォーマット %H:%M の略称 |
%S | 現在の時間の秒、範囲は 00-60 。60 は主にうるう秒を考慮しています |
%t | タブ文字 \t |
%T | フォーマット %H:%M:%S の略称 |
%u | 一週間の何日か、つまり曜日、範囲は 1–7 。週は月曜日から始まります |
%U | 一年の何週か、範囲は 00-53 。最初の週は最初の日曜日から始まります |
%V | 一年の何週か、範囲は 01-53 。最初の週は最初の月曜日から始まります |
%w | 一週間の何日か、つまり曜日、範囲は 0–6 。週は日曜日から始まります |
%W | 一年の何週か、範囲は 00-53 。最初の週は最初の月曜日から始まります |
%x | ローカライズされた完全な日付表示、例えば %A %B %d %Y 、例えば 木曜日 5月 30 2019 |
%X | ローカライズされた完全な時間表示、C 言語の %T に似ています、例えば 07:06:05 |
%y | 2 桁の 10 進年、つまり年の後の 2 桁を取得、範囲は 00-99 、例えば 2019 は 19 を返します |
%Y | 完全な 4 桁の 10 進年、例えば 2019 |
%z | +HHMM 形式のタイムゾーンオフセット。これは RFC 822 または RFC 1036 日付形式の一部です。 |
%Z | タイムゾーン名またはタイムゾーン名の略称。タイムゾーンがない場合は空文字列 '' を返します。 |
その他の関数#
関数 | 説明 |
---|
close(expr) | 既に開いているファイルまたはパイプを閉じるために使用します。 |
system(command) | システムスクリプトコマンドを実行し、スクリプトの実行の終了ステータスを返します。 |
getline | 次の行を読み取ります。 |
next | 次の行を処理します。 |
nextfile | 次のファイルを処理します。 |
# close(expr)
[root@localhost ~]# awk 'BEGIN{while("cat emp.txt" | getline){print $0}close("emp.txt")}'
# system(command)
[root@localhost ~]# awk 'BEGIN{system("ls -l")}'
# getline
[root@localhost ~]# awk '{getline;print}' emp.txt
002 李四 2000 10
004 赵六 2000 20
006 小丽 800 20
[root@localhost ~]# awk 'BEGIN{print "入力:";getline name;print name}'
入力:
123
123
# next
[root@localhost ~]# awk '{if($3<2000)next;print}' emp.txt
002 李四 2000 10
003 王五 3000 10
004 赵六 2000 20
# nextfile
[root@localhost ~]# awk '{if($3==2000) nextfile;print}' emp.txt file
001 张三 1000 10
xxx is a hanhan. ^_^
are you kidding?
I think ...
My phone number is 1872272****.
カスタム関数#
function 関数名(引数1, 引数2, ...) {
関数本体
}
- 関数名は文字で始まる必要があり、文字、数字、アンダースコアで構成できます。予約語は使用できません。
- 関数本体の文はセミコロンで区切る必要があります。
- 関数は戻り値を持つことも、持たないこともできます。戻り値が必要な場合は、大括弧内で
return
キーワードを使用する必要があります。
# 引数なしの関数を呼び出す
fun_name
# 引数ありの関数を呼び出す
fun_name(arg1[,arg2...])
# 戻り値のある関数を呼び出す
var = fun_name([arg1...])
関数は BEGIN
、本体
, END
の中で呼び出すことができます。
# 引数なしの関数
[root@localhost ~]# awk 'BEGIN{
fun1()
}
function fun1(){
print "これは関数です!"
}'
これは関数です!
# 引数ありの関数
[root@localhost ~]# awk 'BEGIN{
fun2(10,20)
}
function fun2(num1,num2){
print "関数の実行結果は:"num1+num2
}'
関数の実行結果は:30
# 戻り値のある関数
[root@localhost ~]# awk 'BEGIN{
res = fun3(10,20);
print "num1+num2の和は:"res
}
function fun3(num1,num2){
return num1+num2
}'
num1+num2の和は:30