LoginSignup
2
1

More than 5 years have passed since last update.

sed と awk (4)sed - print and substitute

Posted at

最初のサンプル

プリントコマンド

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 に保存していない限り結果はかわらなさそう。もう少ししたらわかるかな。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1