はじめに
SED AWKについて新しく知ったことや改めて知ったことをその都度だらだらと追記していくページになります。皆様からしてみれば大変読みにくいかと存じますが、ご容赦下さい。この中の何か一つでも糧になればと思います。
SED概要
パターンスペース
インプット情報を1行ずつパターンスペースというバッファみたいなところにコピーして、そのパターンスペースに対して各コマンドで操作・編集を行い、最終的にアウトプットされる。
書式
置換
/[address]/s/pattern/replacement/flags
- flags
- n
- パターンにマッチするn番目のみ置換
- g
- パターンにマッチする全てを置換
- p
- パターンスペースの内容を表示
- w file
- パターンスペースの内容をファイルに書き出し
- n
範囲抽出①
アドレスをカンマ区切りで2つ並べると、一つ目から二つ目までの行を抽出して出力する。
$ cat list
John Daggett, 341 King Road, Plymouth MA
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
$ sed -n /^Alice/,/^Terry/p list
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
-n
は標準で全文出力の機能をオフにするオプション。p
という表示コマンドで明示した物以外を表示しなくなる。確証はないのですがaddress1にマッチしてaddress2にマッチしない場合は、address1にマッチした箇所から以下全てが対象になる…?
範囲抽出②
N
コマンドでパターンスペースに次の1行を追加出来る。これを使えば複数行のパターンマッチングを行える。次は名前解決の失敗した部分のみを抽出している。(N
コマンドを3つ実行しているので合計4行のパターンスペースとなる。)
GNU SEDなら-z
オプションでコマンドの影響範囲を標準入力全体に出来る。
$ cat testfile
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65321
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hoge.com. IN A
;; ANSWER SECTION:
hoge.com. 86400 IN A 172.16.0.1
;; AUTHORITY SECTION:
hoge.com. 86400 IN NS ns.hoge.com.
;; ADDITIONAL SECTION:
ns.hoge.com. 86400 IN A 172.16.0.2
;; Query time: 2 msec
;; SERVER: 10.0.10.123#53(10.0.10.123)
;; WHEN: 水 6月 03 07:18:57 UTC 2020
;; MSG SIZE rcvd: 86
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10136
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hoge.com. IN A
;; ANSWER SECTION:
hoge.com. 86400 IN A 172.16.0.1
;; AUTHORITY SECTION:
hoge.com. 86400 IN NS ns.hoge.com.
;; ADDITIONAL SECTION:
ns.hoge.com. 86400 IN A 172.16.0.2
;; Query time: 46 msec
;; SERVER: 10.0.10.123#53(10.0.10.123)
;; WHEN: 水 6月 03 07:20:19 UTC 2020
;; MSG SIZE rcvd: 86
$ sed -n -e 'N;N;N;/.*DiG.*\n.*server.*\n.*global.*\n.*reach.*/p' testfile
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
複数行置換
Johnで始まる行からOrvilleで始まる行を消去する場合。
$ cat list_2
John Daggett, 341 King Road, Plymouth MA
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
John Daggett, 341 King Road, Plymouth MA
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
$ sed /^John/,/^Orville/s/.*//g list_2
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
行置換/文字列置換/削除コマンド
パターンを指定しなければアドレスにマッチした行全体を空文字に置換し、指定した場合は文字列を置換する。また削除コマンドを使った場合は行自体が削除される。
①
$ sed /.*MA/s///g list
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
②
$ sed /.*MA/s/MA//g list
John Daggett, 341 King Road, Plymouth
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston
②‘正規表現を変更
$ sed /MA/s///g list
John Daggett, 341 King Road, Plymouth
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston
③
$ sed /.*MA/d list
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
表示コマンド
$ cat sed5
/^John/{
p
s/John//p
}
$ sed -n -f sed5 list
John Daggett, 341 King Road, Plymouth MA
Daggett, 341 King Road, Plymouth MA
3行目の表示コマンドと4行目の置換コマンドの表示フラグの違いは、後者は置換が成功した場合のみ表示する点。
行番号表示コマンド
$ cat sed6
/.*MA/{
=
p
}
$ sed -n -f sed6 list
1
John Daggett, 341 King Road, Plymouth MA
5
Eric Adams, 20 Post Road, Sudbury MA
8
Sal Carpenter, 73 6th Street, Boston MA
次行読み込み
パターンマッチした次の行を制御する。
$ cat sed7
/.*MA/{
n
/.*/d
}
$ sdiff <(sed -f sed7 list) <(cat list)
John Daggett, 341 King Road, Plymouth MA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
ファイル読み出し
list2ファイルのColumnにマッチした行の後ろにlistファイルの内容を追加する。
$ cat list2
Column1 Column2 Column3 Column4
$ sed '/Column/r list' list2
Column1 Column2 Column3 Column4
John Daggett, 341 King Road, Plymouth MA
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
グループ化
\(\)
で囲んだ部分をグループして後から\番号
で参照出来ます。簡単な例は次の通りです。abc???をabcabcabcabcにします。
$ echo "abcdef" | sed -e 's/\(abc\).*/\1\1\1\1/'
abcabcabcabc
果たしてこれが何の役に立つのやらと思うかもしれません。こんな時に役に立つのではないでしょうか…?
次の部分を
$ cat testcss
.form {
font-size: 40px;
}
下の様に変換したい場合
.form {
font-size: 20px;
}
次のコマンドで可能です
$ cat testcss | sed -e 'N;N;s/\(\.form {\n.*font-size: \).*\n}/\1 20px;\'$'\n}/'
.form {
font-size: 20px;
}
macのsed
※BSD sed は少し特殊…
タブ入力
Ctrl + v をしてからタブ入力する。
改行出力
$ cat list2
Column1 Column2 Column3 Column4
$ sed s/" "/\\$'\n'/2 list2
Column1 Column2
Column3 Column4
もしくは
$ cat list2 | sed -e 's/ /\'$'\n/2'
Column1 Column2
Column3 Column4
よく分からないですが\'$'\n
で改行が出力出来るみたいです。
挿入/追加
$ sed '1i\
\
List\
' list
List
John Daggett, 341 King Road, Plymouth MA
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Ralls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
※iをaに変えれば追加になる
macにGNU SEDをインストールする
$ homebrew install gnu-sed
$ vi ~/.bashrc_profile
alias sed='gsed'
AWKと連想配列
AWKひいてはシェル芸と連想配列の関係は切ってもきれない中です。知っておいて損はありません。例えば次の様にデータを整形して下さいと言われた場合どうしますか?
$ cat data1
hoge 2
moge 3
hoge 5
moge 7
hoge 11
hoge 13
これを下みたいにして下さい。
hoge 2 5 11 13
moge 3 7
連想配列を使うとワンライナーで書くことが可能です。
$ cat data1 | awk '{d[$1]=d[$1]" "$2}END{for(i in d){print i d[i]}}'
hoge 2 5 11 13
moge 3 7
連想配列はインデックスが文字列であること、AWKにおける空白は連節演算子であることの2点を知っていれば、上のコマンドは理解に難くないと思います。
dig結果を降順に並び替え
次の様なデータがあります。dig
コマンド2回分の結果をリダイレクトした物です。ファイルが作成された順に並んでいるのを逆順に並び替えてみます。
$ cat testfile
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57116
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hoge.com. IN A
;; ANSWER SECTION:
hoge.com. 86400 IN A 172.16.0.1
;; AUTHORITY SECTION:
hoge.com. 86400 IN NS ns.hoge.com.
;; ADDITIONAL SECTION:
ns.hoge.com. 86400 IN A 172.16.0.2
;; Query time: 4 msec
;; SERVER: 10.0.10.123#53(10.0.10.123)
;; WHEN: 水 6月 03 07:21:36 UTC 2020
;; MSG SIZE rcvd: 86
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> @10.0.10.123 hoge.com A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62486
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hoge.com. IN A
;; ANSWER SECTION:
hoge.com. 86400 IN A 172.16.0.1
;; AUTHORITY SECTION:
hoge.com. 86400 IN NS ns.hoge.com.
;; ADDITIONAL SECTION:
ns.hoge.com. 86400 IN A 172.16.0.2
;; Query time: 2 msec
;; SERVER: 10.0.10.123#53(10.0.10.123)
;; WHEN: 水 6月 03 07:21:37 UTC 2020
;; MSG SIZE rcvd: 86
実はワンライナーで出来ちゃいます。
$ cat testfile | sed -e '/^$/d' -e '/.*DiG.*/i\\n' | sed -e '/^$/{N;/^\n$/D}' | sed -e '1d' | awk 'BEGIN{RS="";FS="\n"}{a[NR]=$0}END{for(i=NR; i>1; i--){print a[i] "\n"}}'
sed -e '/^$/d' -e '/.*DiG.*/i\\n'
- 空行を削除し「DiG」を含む行の上に空行を追加
sed -e '/^$/{N;/^\n$/D}'
- 連続する空行の一つ目の空行を削除(複数行用削除コマンド
D
) - 改めてパイプで区切る理由は概要セクションより
- 連続する空行の一つ目の空行を削除(複数行用削除コマンド
sed -e '1d'
- 先頭の空行削除
- awk部分
- RSを空行、FSを改行に設定(デフォはRSが改行、FSは空白)
- 各レコード(ブロック)を配列に代入
- 末尾から順に表示