sedコマンドによるファイルの書き換え

シェルスクリプトによってファイルを書き換えます。

  1. sedコマンドの概要
  2. 具体例一覧
    1. 特定の数値を変えたい場合
    2. 特殊文字(/等)を含む文字列の変更
    3. 置換する数値を変数での指定
    4. ある数値以降を全て変更したい
    5. ファイルの空白行の削除
    6. ファイルの行頭に数値を入れる
    7. ファイルの最後に改行を入れる
    8. 繰り返し変更したい場合

    9. do文で何回も変更したい
    10. 全く違う変数を繰り返し代入したい
    11. 整数の変数を規則的に何回も変更したい
    12. 小数点を含む変数を規則的に何回も変更したい
    13. あるディレクトリ以下にある全ファイルを変数にしたい

sedコマンドの概要


対象とするファイル名”input.ini”の中身に

&input
 a=7,
 b=13,
 c='./dat/',
&end

という文が書いてあるとします。
これのファイルの中身を端末からのコマンドで書き換えるためにはsedコマンドを利用します。

sedコマンドとは、置換用のコマンドです。
例えば、コマンドライン上で

sed -e "s/a=7/a=9/" ./input.ini

と入力すると”input.ini”の中身の”a=7″に一致する場所を”a=9″に置換して出力します。
ここで重要なのが、”a=7″に一致する場所だけなので、後ろにあるコンマは影響されません
実際に実行してみると

$ sed -e "s/a=7/a=9/" ./input.ini
&input
 a=9,
 b=13,
 c='./dat/',
&end

となってコマンドライン上に出力されます。
この時、書き換わった内容はコマンドラインのみに出力されるため、元のファイル自体に書き換えはされません

元のファイルの書き換えを行いたければ、出力先を適当なファイル、例えば”tmp”というファイルにし、それを”input.ini”にリネームすればいいです。
すなわち、

sed -e "s/a=7/a=9/" ./input.ini > tmp
mv tmp input.ini

とすればいいのです。実際に実行して中身を見ますと

$ sed -e "s/a=7/a=9/" ./input.ini > tmp
$ mv tmp input.ini
$ cat input.ini
&input
 a=9,
 b=13,
 c='./dat/',
&end

となります。

sedコマンドの概要はここで終了です。
以降は具体例とシェルスクリプトのコード(ファイル名”q.sh”),実行例を載せていきます。

特定の数値を変えたい場合


対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
sed -e "s/a=7/a=9/" ./input.ini > tmp
mv tmp input.ini

実行例

$ sh q.sh
$ cat input.ini
&input
 a=9,
 b=13,
 c='./dat/',
&end

特殊文字(/等)を含む文字列の変更


sedコマンドを使うために/を使います。ならば/を置換したい場合どうすればいいでしょう。
この時はsedコマンドで使っている区切りを表す/を別の特殊文字(例えば%)に置き換えればよいです。

対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
sed -e "s%c='./dat/'%c='./data/'%" input.ini > tmp
mv tmp input.ini

実行例

$ sh q.sh
$ cat input.ini
&input
 a=7,
 b=13,
 c='./data/',
&end

置換する数値の変数での指定


対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
pr=5
sed -e "s/a=7/a=${pr}/" ./input.ini > tmp
mv tmp input.ini

実行例

$ sh q.sh
$ cat input.ini
&input
 a=5,
 b=13,
 c='./dat/',
&ends

ある数値以降を全て変更したい


コンマも含めて消したいとします。
対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
sed -e "s/c=.*/c=12345/" ./input.ini > tmp
mv tmp input.ini

実行例

$ sh q.sh
$ cat input.ini
&input
 a=7,
 b=13,
 c=12345
&end

ファイルの空白行の削除


ファイルに含まれる空白行を全て削除します。
対象とするファイル”input.ini”

&input
 a=7,

 b=13,

 c='./dat/',


&end

“q.sh”の中身

#!/bin/sh
sed -e '/^ *$/d' input.ini > tmp
mv tmp input.ini

実行例

$ sh q.sh
$ cat input.ini
&input
 a=7,
 b=13,
 c='./dat/',
&end

ファイルの行頭に数値を入れる


対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
i=1
while [ ${i} -le 1000 ]
do
    sed -e "${i}s/^/${i} /" input.ini > temp
    mv temp input.ini

    i=`expr $i + 1`
done

実行例

$ sh q.sh
$ cat input.ini
1 &input
2  a=7,
3  b=13,
4  c='./dat/',
5 &end
6

“q.sh”中、1000をファイルに応じて変更してください。

※また、行番号を入れるだけの場合、catコマンドを利用して、

cat -b input.ini > tmp
mv tmp input.ini

とするのが簡単だと思います。
オプション”-b”は空行を含めず行番号を付けるという意味です。空行を含めたい場合は”-n”でできます。

ファイルの最後に改行を入れる


対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
sed '$a\\n' input.ini > tmp
mv tmp input.ini

実行例

$ sh q.sh
$ cat input.ini
&input
 a=7,
 b=13,
 c='./dat/',
&end
   

$

※どうしても2行分改行されてしまうようです。
sedコマンドで1行分の改行は、どうすればよいか分かりませんでした。

苦肉の策ですが、適当なファイル(例えばnn.txt)に改行だけを入力し、catコマンドでファイルを結合すると一応できます。
—nn.txt—

————
を作っておいて、
#!/bin/sh
cat input.ini nn.txt > tmp
mv tmp input.ini
とすれば”input.ini”の後ろに”nn.txt”が結合されるため、1行分の改行が可能です。

do文で何回も変更したい


対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
for pr in 0 1 2
do
    sed -e "s/a=.*/a=${pr},/" input.ini > tmp
    mv tmp input.ini
   
    cat input.ini
done

実行例

$ sh q.sh
&input
 a=0,
 b=13,
 c='./dat/',
&end
&input
 a=1,
 b=13,
 c='./dat/',
&end
&input
 a=2,
 b=13,
 c='./dat/',
&end

全く違う変数を繰り返し代入したい


対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
i=1
for j in 3d0 939d0
do
    echo "count -> ${i}"
    sed -e "s/a=.*/a=${j},/" ./input.ini > tmp
    mv tmp input.ini
   
    grep "a=" input.ini
   
    i=`expr $i + 1`
done

実行例

$ sh q.sh
count -> 1
 a=3d0,
count -> 2
 a=939d0,
$

シェルスクリプトの中の”grep”は”a=”に一致する行を書き出させるものです。

整数の変数を規則的に何回も変更したい


対象とするファイル”input.ini”

&input
 a=7,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
i=1
while [ ${i} -le 3 ]
do
    echo "count -> ${i}"
    sed -e "s/a=.*/a=${i},/" ./input.ini > tmp
    mv tmp input.ini
   
    grep "a=" input.ini
   
    i=`expr $i + 1`
done

実行例

$ sh q.sh
count -> 1
 a=1,
count -> 2
 a=2,
count -> 3
 a=3,
$

小数点を含む変数を規則的に何回も変更したい


小数点を含む演算は”expr”コマンドではできません。
シェルスクリプトで数値計算を行う”bc”コマンドを用いましょう。
ここでは、変数\(v\)に、
\(v=i\times0.7,\;\;(i=1,2,3)\)
を代入する演算を考えましょう。

対象とするファイル”input.ini”

&input
 a=3,
 b=13,
 c='./dat/',
&end

“q.sh”の中身

#!/bin/sh
i=1
while [ ${i} -le 3 ]
do
    echo "count -> ${i}"

    v=$(echo "scale=3; $i*0.70 " | bc | sed -e 's/^\./0./g')
    echo "$v"
   
    sed -e "s/a=.*/a=${v},/" ./input.ini > tmp
    mv tmp input.ini
   
    grep "a=" input.ini
   
    i=`expr $i + 1`
done

実行例

$ sh q.sh
count -> 1
0.70
 a=0.70,
count -> 2
1.40
 a=1.40,
count -> 3
2.10
 a=2.10,
$

あるディレクトリ以下にある全ファイル名を変数にしたい


状況

.
├── a.sh
├── dat
├── data
│   ├── asdfgh.d
│   ├── qwerty.d
│   └── zxcvbn.d
└── input

inputの中身

&input
  filename="./data/xxxxx.d",
  key = 0,
&end

a.shの中身

#!/bin/sh
i=1
for j in ./data/*
do
    sed -e "s%filename=.*%filename="${j}",%" input > tmp
    mv tmp ./dat/${j##*/}_ex
    echo ${j##*/}
    grep "filename=" ./dat/${j##*/}_ex
done

———————-

a.sh実行

$sh a.sh
asdfgh.d
  filename="./data/asdfgh.d",
qwerty.d
  filename="./data/qwerty.d",
zxcvbn.d
  filename="./data/zxcvbn.d",

a.sh実行後の構成

.
├── a.sh
├── dat
│   ├── asdfgh.d_ex
│   ├── qwerty.d_ex
│   └── zxcvbn.d_ex
├── data
│   ├── asdfgh.d
│   ├── qwerty.d
│   └── zxcvbn.d
└── input

例えばdat/asdfgh.d_exの中身

&input
  filename="./data/asdfgh.d",
  key = 0,
&end

参考先


フィルタを使用した文字列操作 1 -UNIX & Linux コマンド・シェルスクリプト リファレンス
sed の使い方 -サーバエンジニアの知恵袋
制御構文 -シェルスクリプト入門
How to pass results of bc to a variable – Ask Ubuntu
bcによる少数の演算 -SWEng TIPs


コメントを残す

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