最初のサンプル
プリントコマンド
p
コマンドを指定すると、現在の pattern space を表示する。ただし、課題があって、下記のように2行ずつ出てくる。なぜ2行出てくるか?というと、stdout と pattern space の両方がデフォルトで表示されてしまうから。
$ sed 'p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
:
ちなみに、pattern space
はなんだろな?と思ったのだけど、これは、sed 内のバッファのことで、ファイルなどから読み取ると、バッファに入るけどそのことらしい。
それを止めるためには、上のマニュアルに表記があるけど、-n
を使うと、自動でのpattern space の表示をやめるので、1行のみになる。
$ sed -n 'p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
ちなみに、Range や、Pattern も指定することができる。最初のは何行目を表示するか?
$ sed -n '1,3 p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
$ sed -n '/^root/ p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
print コマンド 他のパターン
test を使ってみる
#start
start end
start end
startend
b
#bb
bbb
# end
ab12 7af
a234 7ef
5行目から最後$
まで
$ sed -n '5,$ p ' test
b
#bb
bbb
# end
ab12 7af
a234 7ef
正規表現も使う。/ /
でくくって使う
$ sed -n '/^a/ p ' test
ab12 7af
a234 7ef
$ sed -n '/^a[0-9]/ p ' test
a234 7ef
substitute コマンド
s コマンドは置換する。s に続く文字がデリミタになる。大抵は/
を使う。下記のコマンドは、特定の範囲の<string>
を<replacement>
で置き換える。
$ sed ' [range] s/<string>/<replacement>/ ' /etc/passwd
デリミタは/
以外にしても良いので下記のようなものも良い。下記のものは、tsuyoshiで始まる行の/bin/bash
を/bin/sh
に置き換えている
$ sed ' /^tsuyoshi/ s@/bin/bash@/bin/sh@ ' /etc/passwd
サンプル
こんなシェルファイルがあります。nl は標準出力に行番号を添付して送るコマンドです。
$ nl parsecsv.sh
1 #!/bin/bash
2 OLDIFS=$IFS
3 IFS=","
4 while read product price quantity
5 do
6 echo -e "\e[1;33m$product \
7 ========================\e[0m\n\
8 Price : \t $price \n\
9 Quantity : \t $quantity \n"
10 done < $1
11 IFS=$OLDIFS
指定した行にインデントをつける
レンジを指定して、sコマンドで、先頭行をスペースに置換すればOKです。最後の、gは、hold space をpattern space にコピーもしくは追加するためのコマンドです。両方のコンセプトは次の記事が良い感じです。ホールドスペースは、保存用の領域で、h
コマンドで、pattern space から、hold space に保存することができます。
$ sed ' 6,9 s/^/ /g' parsecsv.sh
# !/bin/bash
OLDIFS=$IFS
IFS=","
while read product price quantity
do
echo -e "\e[1;33m$product \
========================\e[0m\n\
Price : \t $price \n\
Quantity : \t $quantity \n"
done < $1
IFS=$OLDIFS
同じ感じで、自動での、pattern space 出力をやめて、p
オプションで、現在のpattern space の出力を指定すると、マッチした部分のみの表示になります。
$ sed -n ' 6,9 s/^/ /p' parsecsv.sh
echo -e "\e[1;33m$product \
========================\e[0m\n\
Price : \t $price \n\
Quantity : \t $quantity \n"
先ほど習った通り、デリミタが/
で都合が悪い時は他のものも使えます。パスなどはその典型例です。
$ sed -n ' /^azure/ s@/bin/bash@/bin/sh@p ' /etc/passwd
azureuser:x:1000:1000:Ubuntu:/home/azureuser:/bin/sh
まとめ
まだ、先ほどの、g
を指定した意義がわかっていません。実際無くしても結果は同じだし、hold space に保存していない限り結果はかわらなさそう。もう少ししたらわかるかな。