sed awk 覚え書き

はじめに

SED AWKについて新しく知ったことや改めて知ったことをその都度だらだらと追記していくページになります。皆様からしてみれば大変読みにくいかと存じますが、ご容赦下さい。この中の何か一つでも糧になればと思います。

SED概要

パターンスペース

インプット情報を1行ずつパターンスペースというバッファみたいなところにコピーして、そのパターンスペースに対して各コマンドで操作・編集を行い、最終的にアウトプットされる。

書式

置換
/[address]/s/pattern/replacement/flags
  • flags
    • n
      • パターンにマッチするn番目のみ置換
    • g
      • パターンにマッチする全てを置換
    • p
      • パターンスペースの内容を表示
    • w file
      • パターンスペースの内容をファイルに書き出し

範囲抽出①

アドレスをカンマ区切りで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は空白)
    • 各レコード(ブロック)を配列に代入
    • 末尾から順に表示

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA