このテキストは、 gawk Witchとして知られるawkのGNU実装のみを指します。
[GNU AWWユーザーガイド] [GNU-AWK]は、[Stackoverflow] [So]の回答から主に撮影した実際のケースを使用した例として、その参照です。
awkはPerlに似た言語であり、かなりエレガントです。
- アーノルド・ロビンズ
awkは、テキスト処理用に設計されたプログラミング言語であり、通常はデータ抽出およびレポートツールとして使用されます。これは、ほとんどのUNIXのようなオペレーティングシステムの標準機能です。
awk賞名...その名前は、著者の姓であるAlfred A Ho、Peter W Einberger、Brian K Ernighanに由来しています。
awk ...ファイルまたは標準入力に特定のパターンを含む行を検索します。
主に、他のユーティリティプログラムの出力から情報を要約するなど、データ抽出とレポートに使用されます。
C-like構文。
データ駆動型:操作したいデータと、見つけたときにどのようなアクションを行うかを説明しています。
pattern { action }
pattern { action }プログラムが短い場合:
awk ' program ' input-file1 input-file2注:シェルを引用して問題に注意してください1 。
cmd | awk ' program '注: pipe 、左側のコマンド( cmd )の出力をawkコマンド2の入力にリダイレクトします。
コードが長い場合、通常、コードをファイルに入れて、次のようなコマンドで実行する方が便利です。
awk -f program-file input-file1 input-file2
cmd | awk -f program-fileまたは、 shebangのように実行可能にするだけです:
#! /bin/awk -f
BEGIN { print " hello world!! " }-F fs FS変数をfsに設定します。
-v var=valプログラムが開始される前に、変数varを値valに設定します。
注:毎回別の変数を設定して、複数回使用できます。
これらの特別なパターンまたはブロックは、 awkプログラムのスタートアップおよびクリーンアップアクションを提供します。
BEGIN{
// initialize variables
}
{
/pattern/ { action }
}
END{
// cleanup
}BEGIN 、すべての入力が消費された後にEND 。
$ echo " hello " | awk ' BEGIN{print "BEGIN";f=1}
{print $f}
END{print "END"} '
BEGIN
hello
ENDawkを持っているのになぜgrepping ? $ cat lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ grep dolor lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.$ awk ' /dolor/ ' lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.注:アクションが与えられていない場合、デフォルトのアクションは、指定されたパターンに一致するレコードを印刷することです。
しかし...どのようにして各行の最初と最後の単語を見つけることができますか?
もちろん、 grepできますが、2つのステップが必要です。
$ grep -Eo ' ^[^ ]+ ' lorem_ipsum.dat
Lorem
Maecenas
Nunc
Curabitur
Lorem
Aliquam$ grep -Eo ' [^ ]+$ ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
ultrices.ここでawkが動作しているのを見てみましょう:
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices. awk 、プログラムの入力をレコードとフィールドに分割します。
レコードは、レコードセパレーターRSと呼ばれるキャラクターによって区切られています。デフォルトでは、レコードセパレーターはUnix Newline Character nです。
これが、レコードがデフォルトで単一行である理由です。
さらに、 awkにはORS出力レコードセパレーターがあり、レコードがstdoutに表示される方法を制御します。
RSおよびORS引用符で囲まれている必要があります。これは、文字列定数を示すものです。
別の文字または正規表現を使用するには、単にRSまたは /およびORS変数に割り当てるだけです。
BEGINため、最初のレコードは適切なセパレーターで読まれます。例:
$ awk ' BEGIN{RS=" *, *";ORS="<<<---n"}
{print $0} ' lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- $ awk ' {print $0} ' RS= " *, * " ORS= " <<<---n " lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- awkレコードは、自動的に解析されるか、フィールドと呼ばれるチャンクに分離されます。
デフォルトでは、フィールドは、単語のように、 Whitespace (1つ以上のスペース、タブ、またはNewLinesの文字列)で区切られています。
awkプログラムのフィールドを参照するには、Dollar $ signを使用して、その後に必要なフィールドの数を使用します。
したがって、 $1最初のフィールド、2番目に$2などを指します。
重要: $0入力レコード全体を表します。
$ awk ' {print $3} ' lorem_ipsum.dat
dolor
erat
orci,
dapibus
dolor
mauris NFは事前定義された変数です。値は現在のレコードのフィールドの数です。したがって、 $NF常にレコードの最後のフィールドになります。
$ awk ' {print NF} ' lorem_ipsum.dat
8
7
10
4
8
10vs。
$ awk ' {print $NF} ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
facilisis. FSフィールドセパレーターの価値を保持します。この値は、入力レコードのフィールド間の分離に一致する単一の文字列またはregexです。
デフォルト値は" "で、単一のスペースで構成される文字列です。特別な例外として、この値は、一連のスペース、タブ、および/またはニューラインが単一のセパレーターであることを意味します。
同じ方法で、 OFS変数があり、フィールドORSどのように出力ストリームに送信されるかを管理します。
$ cat /etc/group
nobody: * :-2:
nogroup: * :-1:
wheel: * :0:root
daemon: * :1:root
kmem: * :2:root
sys: * :3:root
tty: * :4:root$ awk ' !/^(_|#)/&&$1=$1 ' FS= " : " OFS= " <-> " /etc/group
nobody < - > * < - > - 2< - >
nogroup < - > * < - > - 1< - >
wheel < - > * < - > 0 < - > root
daemon < - > * < - > 1 < - > root
kmem < - > * < - > 2 < - > root
sys < - > * < - > 3 < - > root
tty < - > * < - > 4 < - > root注:うーん... $1=$1 ???? 3
レコードとフィールドを念頭に置いて、以前のコードを理解する準備が整いました。
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices.これらは、2つの便利な組み込み変数です。
NR :プログラムの実行の開始以来、 awkが処理した入力レコードの数。
FNR :現在のファイルの現在のレコード番号は、新しい入力ファイルawk起動するたびにFNRをゼロにリセットします。
$ cat n1.dat
one
two$ cat n2.dat
three
four$ awk ' {print NR,FNR,$0} ' n1.dat n2.dat
1 1 one
2 2 two
3 1 three
4 2 fourフォーマット文字列は、ISO cの文字列と非常に似ています。
構文:
printf format, item1, item2, …
$ awk ' {printf "%20s <-> %sn",$1,$NF} ' lorem_ipsum.dat
Lorem < - > elit.
Maecenas < - > condimentum.
Nunc < - > ex.
Curabitur < - > tellus.
Lorem < - > elit.
Aliquam < - > ultrices.printおよびprintfからの出力は、デフォルトで標準出力に向けられますが、リダイレクトを使用して宛先を変更できます。
awkのリダイレクトは、 awkプログラム内で書かれていることを除いて、シェルコマンドのリダイレクトと同じように書かれています。
$ awk ' BEGIN{print "hello">"hello.dat"} ' $ awk ' BEGIN{print "world!">>"hello.dat"} ' $ cat hello.dat
hello
world !パイプを介して別のプログラムに出力を送信することも可能です。
$ awk ' BEGIN{sh="/bin/sh";print "date"|sh;close(sh)} '
dom nov 13 18:36:25 CET 2016 [ストリーム]は、 stdin 、 stdoutおよびstderrを指すことができます。
たとえば、このようにstderrにエラーメッセージを書くことができます。
$ awk ' BEGIN{print "Serious error detected!" > "/dev/stderr"} '
Serious error detected ! awkでは、配列は連想的であり、それぞれがペア、インデックス-値のコレクションであり、任意の数字または文字列がインデックスになります。
宣言は必要ありません。新しいペアはいつでも追加できます。
| 索引 | 価値 |
|---|---|
| 「ペロ」 | "犬" |
| 「ガト」 | "猫" |
| 「UNO」 | "1つ" |
| 1 | "1つ" |
| 2 | "二" |
配列を参照するには:
array[index-expression]
値を割り当てるには:
array[index-expression] = value
キーがインデックス化されているかどうかを確認するには:
indx in array
反復するには:
for (var in array) {
var, array[var]
}数値値をインデックスとして使用し、順序を維持します。
for (i = 1 ; i < = max_index ; i++) {
print array[i]
}完全な例:
$ cat dict.dat
uno one
dos two
tres three
cuatro fourawk ' {dict[$1]=$2}
END{if ("uno" in dict)
print "Yes we have uno in dict!"
if (!("cinco" in dict))
print "No , cinco is not in dict!"
for (esp in dict){
print esp, "->" ,dict[esp]
}
} ' dict.datあなたに与える:
Yes we have uno in dict !
No , cinco is not in dict !
uno - > one
dos - > two
tres - > three
cuatro - > four gawkデフォルトで配列をソートしません。
awk ' BEGIN{
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 4 four
0 zero
1 one
2 two
3 threeただし、[Procinfo]を利用することができます。
awk ' BEGIN{
PROCINFO["sorted_in"] = "@ind_num_asc"
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 0 zero
1 one
2 two
3 three
4 fourgensub(regexp, replacement, how [, target]) :文字列交換の最も高度な関数です。
そして彼らのより単純な代替案:
gsub(regexp, replacement [, target])
sub(regexp, replacement [, target])
このファイルを持っている:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.各コンマの左右に配置された単語の位置を交換します。
$ awk ' {print gensub(/([^ ]+)( *, *)([^ ]+)/,
"\3\2\1", "g")} ' lorem.dat
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim euismod, orci id nisi interdum, eget cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Aliquam interdum mauris volutpat nisl et, placerat facilisis. gensubを使用して、 3つのグループをキャプチャしてから、注文を交換します。
より単純なアクションを説明するために、コンマのドットを変更しましょう。
awk ' $0=gensub(/./, ",", "g") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis, gsub代替の使用:
awk ' gsub(/./, ",") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis,このオプションは、グループキャプチャが不要な場合に優れているようです。
その他の興味深い関数は、 indexとsubstrです。
index(in, find)
substr(string, start [, length ])
このような作品:
$ awk ' BEGIN{t="hello-world";print index(t, "-")} '
6$ awk ' BEGIN{t="hello-world";print substr(t,index(t, "-")+1)} '
world split関数は、セパレーターチャーで除算する文字列から配列を作成するために使用され、作成された配列の要素の数を返します。
split(string, array [, fieldsep [, seps ] ])
$ cat passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbash$ awk ' n=split($0, a, ":"){print n, a[n]} ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbash注:これは、はるかに簡単な方法で行うことができます。
$ awk ' {print NF,$NF} ' FS= ' : ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbashカスタム関数を書くことは非常に簡単です:
awk ' function test(m)
{
printf "This is a test func, parameter: %sn", m
}
BEGIN{test("param")} '与えてください:
This is a test func, parameter: paramまた、 returnステートメントを使用して式を返すこともできます。
awk ' function test(m)
{
return sprintf("This is a test func, parameter: %s", m)
}
BEGIN{print test("param")} 'パラメーターによる解析は、関数内にローカル変数を作成する唯一の方法です。
スカラー値は参照によって値と配列によって渡されるため、関数内の配列に加えられた変更は、グローバルな範囲に反映されます。
awk ' function test(m)
{
m[0] = "new"
}
BEGIN{m[0]=1
test(m)
exit
}
END{print m[0]} '出力:
new私たちの課題:
01。記録の最後から2番目。
02。レコードの交換。
03。各レコードの最後にセミコロンを置きます。
04。すべての単語の間にコンマを配置します。
05。すべて一緒に?
06.奇数レコードをファイルに、さらには別のファイルにリダイレクトします。
07。パスワードファイルを指定して、欠落フィールドを取得します。
08。フィールドスワッピング。
09。Tracerouteハッキング。
10。私の子供はどこにいますか?
11。データ集約。
12。2つのパターン間の記録。
13。フィールド変換。
14。列へのレコード。
15。FASTAファイル処理。
16。複雑な報告。
17。ファイルジョイナー。
18。PassWDおよびグループ。
19。ユーザー接続。
20。アップタイム合計負荷平均。
このソースファイルを持っている:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' {print $(NF-1)} ' lorem.dat
adipiscing
consectetur
cursus
dapibus
adipiscing
nequeここで説明することはあまりありませんが、 NF現在のレコードにフィールドの数を保存するため、 NF-1最後のフィールドを指し、 $(NF-1)がその価値になります。
私たちのタスク、ファイルレコードの代替、3番目の行は次のようにする必要があります。
This not latin
これ以上単純なことはありませんNR (レコード数)の周りでプレイしてください。
コード:
$ awk ' NR==3{print "This is not latin";next}{print} ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis. nextステートメントを回避するための代替ソリューション:新しい行を完全な記録に割り当てます$0 。
例:
$ awk ' NR==3{$0="This is not latin"}1 ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' 1 ' ORS= " ;n " lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Maecenas pellentesque erat vel tortor consectetur condimentum. ;
Nunc enim orci, euismod id nisi eget, interdum cursus ex. ;
Curabitur a dapibus tellus. ;
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Aliquam interdum mauris volutpat nisl placerat, et facilisis neque ultrices. ;デフォルトのRSはUNIXブレークラインnであるため、Semicolonを出力レコードSeparator OFSにプレフィックスする必要があります。
1どうですか? 4
$ awk ' {$1=$1}1 ' OFS= ' , ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum.
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex.
Curabitur,a,dapibus,tellus.
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices.このコードの最も重要な部分は、 OFSの現在の値に対して$1=$1でレコード再構成を強制する方法です。
$ awk ' {$1=$1}1 ' OFS= ' , ' ORS= ' ;n ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum. ;
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex. ;
Curabitur,a,dapibus,tellus. ;
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices. ; output vars: OFS and ORSで遊ぶだけのように。
最終的な解決策から始めましょう。
$ awk ' NR%2{print > "even.dat";next}
{print > "odd.dat"} ' lorem.dat$ cat even.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Lorem ipsum dolor sit amet, consectetur adipiscing elit$ cat odd.dat
Maecenas pellentesque erat vel tortor consectetur condimentum.
Curabitur a dapibus tellus.
Aliquam interdum mauris volutpat nisl placerat, et facilisis. [modulo]関数( % )は、現在のレコード番号NRの分裂後の残りを2つで割ったものを見つけます。
$ awk ' {print NR%2} ' lorem.dat
1
0
1
0
1
0現在の限り、 awk 1では真であり、 0 falseです。この事実を評価する出力をリダイレクトします。
next 、特別な注意が必要であり、 awkはすぐに現在のレコードプロセスを停止し、次のプロセスに渡すことを強制します。
このようにして、私たちは次のように見える二重の状態を避けます:
awk ' NR % 2{print > "even.dat"}
!NR % 2{print > "odd.dat"} ' lorem.dat$ cat /etc/passwd
jd001:x:1032:666:Javier Diaz::/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez::/bin/rbash
jp003:x:1000:666:Jose Perez::/bin/bash
ms004:x:8051:668:Maria Saenz::/bin/rbash
rc005:x:6550:668:Rosa Camacho::/bin/rbash固定された文字列"/home/"ユーザー名に接頭することにより、ホームディレクトリを想定しましょう。
$ awk ' $6="/home/"$1 ' FS= ' : ' OFS= ' : ' /etc/passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbash私たちの最初のステップは、入力と出力のために、コロンであるフィールドセパレーターを検討することです。
次に、この例では、 6フィールドの位置を見つける必要があります。
最後に、指定された文字列と最初のフィールドに保存されたユーザーログインを使用して必要な値を作成します。
$6割り当て返品値は常に真であり、 awkデフォルトアクションが影響を受けるレコードを印刷するため、 print必要ありません。
私たちの目標:最後のフィールドが最初になり、最初に最後になるはずです。
最終コード:
$ awk -F : ' {last=$1;$1=$NF;$NF=last}1 ' FS= " : " OFS= ' : ' /etc/passwd
/bin/rbash:x:1032:666:Javier Diaz:/home/jd001:jd001
/bin/rbash:x:8050:668:Alejandro Gonzalez:/home/ag002:ag002
/bin/bash:x:1000:666:Jose Perez:/home/jp003:jp003
/bin/rbash:x:8051:668:Maria Saenz:/home/ms004:ms004
/bin/rbash:x:6550:668:Rosa Camacho:/home/rc005:rc005最初のフィールド値を保存するために使用される中間変数、最後の変数とその値を交換し、最後にlast変数を$NF ( $NF=last )に割り当てます。
この出力を持っている:
$ traceroute -q 1 google.com 2> /dev/null
1 hitronhub.home (192.168.1.1) 5.578 ms
2 217.217.0.1.dyn.user.ono.com (217.217.0.1) 9.732 ms
3 10.127.54.181 (10.127.54.181) 10.198 ms
4 62.42.228.62.static.user.ono.com (62.42.228.62) 35.519 ms
5 72.14.235.20 (72.14.235.20) 26.003 ms
6 216.239.50.133 (216.239.50.133) 25.678 ms
7 mad01s24-in-f14.1e100.net (216.58.211.238) 25.019 ms合計時間を移動するパッケージを計算する必要があります。
$ traceroute -q 1 google.com 2> /dev/null |
awk ' {total+=$(NF-1)}
END{print "Total ms: "total} '
Total ms: 153.424条件が指定されていないため、すべてのレコードに対してアクションが実行されます。
total+=$(NF-1) : total変数を使用して、各レコードの最後から2番目のフィールド$(NF-1)の値を蓄積します。
最後に、最終的なtotal値を表示するためにENDルールを使用します。
私たちの仕事: shell依存プロセスを取得します。
$ echo $$
51026まず、背景プロセスを起動します。
$ sleep 10 & sleep 15 & sleep 20 &
[1] 86751
[2] 86752
[3] 86753 psユーティリティを使用して、 awk PPIDと呼ばれる3番目のフィールドを探します。
注:プログラムが開始される前に、 -vを使用してppid varを設定します。
$ ps -ef | awk -v ppid= $$ ' $3==ppid '
501 86751 51026 0 7:57PM ttys001 0:00.00 sleep 10
501 86752 51026 0 7:57PM ttys001 0:00.00 sleep 15
501 86753 51026 0 7:57PM ttys001 0:00.00 sleep 20
0 86754 51026 0 7:57PM ttys001 0:00.00 ps -ef
501 86755 51026 0 7:57PM ttys001 0:00.00 awk $3 ==51026睡眠が必要です:
$ ps -ef | awk -v ppid= $$ ' $3 == ppid && /slee[p]/
{print $2" -> "$5} '
86751 - > 7:57PM
86752 - > 7:57PM
86753 - > 7:57PMソリューションに追加する新しい条件が必要です。現在のレコード/slee[p]/で睡眠パターンを見つけます。
トリガーされたアクションは、 PIDのスタンドと5番目の$5のタイムスタンプで2番目のフィールド$2印刷することです。
このファイルを持っている:
$ cat ips.dat
IP BYTES
81.220.49.127 328
81.220.49.127 328
81.220.49.127 329
81.220.49.127 367
81.220.49.127 5302
81.226.10.238 328
81.227.128.93 84700私たちのタスクは、 IPごとに処理されるバイト数を計算することです。
$ awk ' NR>1{ips[$1]+=$2}
END{for (ip in ips){print ip, ips[ip]}} ' ips.dat
81.220.49.127 6654
81.227.128.93 84700
81.226.10.238 328説明するためにここでたくさんのこと。
NR>1{ips[$1]+=$2} :アクションips[$1]+=$2現在のレコード番号が1つのNR>1を超える場合にのみ実行されます。これは、ヘッダーを避けるために必要です。
ips 、 IP値( $1フィールド)によってインデックス付けされた配列です。各キーについて、2番目のフィールドの値に蓄積します。
重要な事実に注意してください。キーが配列に存在しない場合、 awk構造に新しい要素を追加します。そうでなければ、そのキーによって指し示された以前の値を更新します(例のように)。
ENDルールは、インデックスと値によって配列を反復するために使用されます。
このコードは、配列の使用を避け、ソートされたIPSファイルを利用した順序を保持するために、完全に異なる方法で書き直すことができます。
awk ' NR==1{next}
lip && lip != $1{print lip,sum;sum=0}
{sum+=$2;lip=$1}
END{print lip,sum} ' ips.dat
81.220.49.127 6654
81.226.10.238 328
81.227.128.93 84700 NR==1{next} :ヘッダーをバイパスします。
lip && lip != $1{print lip,sum;sum=0} :ここでは、varという名前のlip ( last-ip )を使用します。 lip && lip != $1 lipがnullではなく、最初のフィールド(現在のIPを保持する)と等しくない場合、トリガーされたアクションは、 lipを印刷して最後のIPの合計バイト量sumことです。次に、 sum=0を初期化します。
トリックは明確で、 IP( $1 )が変更されるたびに、前の統計の統計を表示します。
{sum+=$2;lip=$1} :バイトカウンターsum+=$2を更新し、現在のIPをlip lip=$1に割り当てるには。これは、レコード処理の最後のステップです。
ENDブロックは、保留中の値を印刷するために使用されます。
このコードは順序を保持しますが、私の意見では、これは大幅に複雑さが増加することを犠牲にして行われます。
私たちのタスクは、2つの抽出とOUTPUTとEND 。
$ cat pat.dat
test -3
test -2
test -1
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
END
test 1
test 2
test 3これは、 awkでパターンマッチングがどのように機能するかを説明するために使用される古典的な例です。
$ awk ' /END/{flag=0}flag;/OUTPUT/{flag=1} ' pat.dat
top 2
bottom 1
left 0
right 0
page 66 flag変数値に基づいて、開始パターンOUTPUT見つかったときは( 1 ) ENDタグに到達したとき( 0 ) true ( 1 )になります。
追加のステップを回避するために、ロジックシーケンスに従う場合、アクションオーダーは非常に重要です。
$ awk ' /OUTPUT/{flag=1}flag;/END/{flag=0} ' pat.dat
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
ENDパターンタグは出力から表示されます。
理由: OUTPUTパターンが見つかった後、次のアクションがこのフラグに依存するため、フラグがアクティブになります。レコードが印刷されます。
この動作は、フラグのアクティベーションをフローの最後のステップとして配置することを避けることができます。
このファイルを仮定しましょう:
$ cat space.dat
10.80 kb
60.08 kb
35.40 kb
2.20 MB
1.10 MB
40.80 kb
3.15 MB
20.50 kb私たちの仕事は、メガバイトの総重量を計算することです。
$ awk ' {total+= $1 / ($2=="kb" ? 1024: 1)}
END{print total} ' space.dat
6.61365それがどのように機能するかを理解するには、1つの概念が明確でなければなりません。 [Ternary]演算子(古い投稿の主題)。
total 、最初のフィールドのディビゾンを2番目の$2 $1で蓄積するために使用されます1024番目の$2で、 1が指定された値を保持しますkb
最後に、 ENDブロックにtotal値を印刷します。
元の出典:
$ cat group.dat
string1
string2
string3
string4
string5
string6
string8私たちの使命は、このような3つの列のブロックに記録をグループ化することです。
string1 string2 string3
string4 string5 string6
string8複雑に思えるかもしれませんが、出力フィールド分離OFSの使用方法を理解すればはるかに簡単になります。
$ awk ' ORS = NR%3 ? FS : RS; END{print "n"} ' group.dat
string1 string2 string3
string4 string5 string6
string8 ORS空白の文字、 FSデフォルト値に設定すると、すべての出力が単一行になります。
$ awk ' ORS=FS; END{print "n"} ' group.dat
string1 string2 string3 string4 string5 string6 string7 ORS = NR%3 ? FS : RS :最後に、最終的なオペレーター(直前に説明)を使用して、現在のフィールド番号NRの分割の[モジュロ] NR%3結果を3回評価します。
残りが真である場合、 ORS FS 、空白スペースになります。そうしないと、 RSデフォルト値が割り当てられます。UNIXLineBreak n 。
バイオインフォマティクスでは、[FASTA]はテキストベースのファイル形式です。
次の例があります:
$ cat fasta.dat
> header1
CGCTCTCTCCATCTCTCTACCCTCTCCCTCTCTCTCGGATAGCTAGCTCTTCTTCCTCCT
TCCTCCGTTTGGATCAGACGAGAGGGTATGTAGTGGTGCACCACGAGTTGGTGAAGC
> header2
GGT
> header3
TTATGAT各シーケンスの全長と最終履歴書が必要です。
このように見えるはずです:
> header1
117
> header2
3
> header3
7
3 sequences, total length 127 awk 、このレポートの取り組みに最適なツールです。この例では、以下を使用します。
awk ' /^>/ { if (seqlen) {
print seqlen
}
print
seqtotal+=seqlen
seqlen=0
seq+=1
next
}
{
seqlen += length($0)
}
END{print seqlen
print seq" sequences, total length " seqtotal+seqlen
} ' fasta.dat
最初のアクションは、ヘッダー検出/^>/に結び付けられています。これは、すべてのヘッダーが>文字を持つ星があるためです。
seqlenその値をnullしない場合、以前のシーケンスの長さを保持している場合、新しいヘッダーに接続されたstdoutに印刷されます。 seqtotalが更新され、次のシーケンスを提供するためにseqlenが初期化されます。最後に、 nextの記録処理を破ります。
2番目のアクション{seqlen += length($0)}合計記録長を合計するseqlen更新するために使用されます。
END規則の目的は、印刷されていないシーケンスと合計を表示することです。
ここでのトリックは、新しいヘッダーを見つけたときに以前のシーケンス長を印刷することです。
最初のレコードを処理すると、 seqlenは価値がないため、視覚化をスキップします。
ソース:
$ cat report.dat
snaps1: Counter: 4966
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 0
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.test.attributes
snaps1: Counter: 5660
Opens: Counter: 37283
Instance: s.1.aps.userDatabase.mount275000.attributes私たちの義務: snapsとinstanceを視覚化するレポートを作成しますが、スナップ最初のカウンタータグがゼロより大きい場合のみです。
予想出力:
snaps1: Counter: 4966
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 5660
Instance: s.1.aps.userDatabase.mount275000.attributes私たちはパターンとフラグを中心に再び遊んでいます:
awk ' {$1=$1}
/snaps1/ && $NF>0{print;f=1}
f && /Instance/ {print;f=0} ' report.datすべてのレコードについて、最初のアクションが実行されると、 OFS 3の現在の値を使用して、 awkレコード全体を再構築することを強制します。
このトリックにより、複数のスペースセパレーターを単一のcharに変換できます。これは、出力フィールドセパレーターのデフォルト値です。
これを見てみましょう:
$ awk ' 1 ' text.dat
one two
three four$ awk ' $1=$1 ' text.dat
one two
three fourパターンが見つかったときに2番目のアクションがトリガーされ、最後のフィールドがゼロ/snaps1/ && $NF>0を超えます。
awkレコードを印刷し、フラグ印刷に真の値を割り当てますprint;f=1 。
最後のステップ:フラグが真であり、ラインf && /Instance/のインスタンスパターンの場合、ラインを表示し、フラグを非アクティブ化: print;f=0 。
2つのアーカイブを想定しましょう。
$ cat join1.dat
3.5 22
5. 23
4.2 42
4.5 44$ cat join2.dat
3.5
3.7
5.
6.5最初のフィールドが2番目のフィールドにあるときに、最初のjoin1.dat join2.datレコードが必要です。
出力は次のとおりです。
3.5 22
5. 23もちろん、 UNIX Joinユーティリティを使用できますが、最初のファイルをソートする必要があります。
$ join <( sort join1.dat ) join2.dat
3.5 22
5. 23 awkでは必要ありません:
$ awk ' NR == FNR{a[$1];next}
$1 in a ' join2.dat join1.datフィルターとアクションを研究しましょう。
NR == FNR :レコードファイル番号に等しいレコード番号は、 awkに解析された最初のファイルを処理することを意味します: join2.dat 。
ペアアクションa[$1];next最初のフィールドによってインデックス付けされたアレイに新しいボイド値を追加することです。 nextステートメントでは、レコード処理を破り、フローを次の声明に渡します。
2番目のアクションの場合、 NR != FNRは暗黙的に適用され、 join1.datにのみ影響します。2番目$1 in aです。これは、 join1.datの最初のフィールドが配列キーである場合に真です。
これらはクラシックをunixすることです:
$ cat /etc/group
dba:x:001:
netadmin:x:002:$ cat /etc/passwd
jd001:x:1032:001:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:002:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:001:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:002:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:002:Rosa Camacho:/home/rc005:/bin/rbash私たちの目標、このようなレポート:
d001:dba
ag002:netadmin
jp003:dba
ms004:netadmin
rc005:netadmin最後の例で調査したように、複数のファイルフローが必要です。
$ awk -F : ' NR == FNR{g[$3]=$1;next}
$4 in g{print $1""FS""g[$4]} ' /etc/group /etc/passwd /etc/groupを処理するには$1 NR == FNR $3を繰り返し、グループの名前g[$3]=$1保存します。最後に、 nextの記録処理を破ります。
2番目の条件は、 /etc/passwdレコードのみをターゲットにします。4番目のフィールド$4 (グループID )がArray $4 in gに存在する場合、グループID g[$4]によってインデックス付けされた配列によって指定print $1""FS""g[$4]れたログインと値を印刷します。
ユーザーユーティリティ出力の例:
$ users
negan rick bart klashxx klashxx ironman ironman ironmanユーザーごとにログオンをカウントします。
$ users | awk ' {a[$1]++}
END{for (i in a){print i,a[i]}} ' RS= ' + '
rick 1
bart 1
ironman 3
negan 1
klashxx 2アクションはすべてのレコードに対して実行されます。
a[$1]++ :これはカウンターであり、各ユーザーの場合、 $1は先の尖った値を増やします(初期化されたVARには数値ゼロがあります)。
ENDにブロックは、キーと保存された値ごとに配列を反復し、結果を提示します。
典型的な出力:
$ uptime
11:08:51 up 121 days, 13:09, 10 users, load average: 9.12, 14.85, 20.84総負荷平均平均をどのように取得できますか?
$ uptime | awk ' {printf "Load average mean: %0.2fn",
($(NF-2)+$(NF-1)+$(NF))/3 } ' FS= ' (:|,) + '
Load average mean: 14.94これが新しいテクニックです。
[Regex]をフィールドセパレーター(:|,) +として使用しているため、 FSコロンとコンマに続いてゼロ以上の空白にすることができます。
必要な算術を実行するために最後の3つのフィールドが必要なだけで、適切なマスクに接続されたprintfを使用します。
あなたがまだここにいるなら、ありがとう!
私の観点から見ると、 awk過小評価されている言語であり、多くの愛が必要です。
あなたがもっと腹を立てているなら、コメントセクションBellowで私にそれを知らせてください、そして私は私の使命を終えるために2番目の部分を検討します...あなたを死に至らします。
ハッピーコーディング!
[Unix Shell Quotingのガイド] [Quoting-Guide]。 ↩
[パイプライン上のウィキペディア] [パイプ]。 ↩
FSとOFSの現在の値を使用して、 awkにレコード全体を再構築するように強制することが便利な場合があります。
これを行うには、一見無害な割り当てを使用します: $1 = $1 1
簡単な答え、それは印刷されたステートメントの使用を避けるための単なる近道です。
awkで条件が一致する場合、デフォルトのアクションは入力行を印刷することです。
$ echo "test" |awk '1'
に相当します:
echo "test"|awk '1==1'
echo "test"|awk '{if (1==1){print}}'
それは、 1常に[True]になるからです。 ↩