LoginSignup
0
0

More than 1 year has passed since last update.

sedで複数行を置換、挿入したいとき【sed, Shell】

Posted at

やりたいこと

次の2つのファイル(文字列)がある

source
hogehoge hugahuga
hogahoga hugehuge
target
AAAAAA
BBBBBB
CCCCCC
FLAG
DDDDDD
EEEEEE

このときにtargetFLAGの部分をsourceの内容で置き換えたい。
つまり、

result
AAAAAA
BBBBBB
CCCCCC
hogehoge hugahuga
hogahoga hugehuge
DDDDDD
EEEEEE

こんな感じ。
これが少し面倒で、詰まったので書き残す。

結論

これでOK

str=`cat source | # 挿入する文字列を読み込み
        sed -r 's/$/\\\\n/' | # 各行の末端に改行文字を入れる
        sed -r '$s/\\\\n//' | # 最終行の改行文字に関しては必要ないので取り除く
        while IFS= read -r line # 1行ずつ読み込み
        do
            echo -n "$line" # echo -nで各行を改行しないで出力->1行にまとめる
        done`
cat target |
    sed -r "/^FLAG$/s/.+/$str/" # sedで必要な部分に挿入(置換)

解説1/3

まずは次のやり方が思いつくと思う。

str=`cat source`
cat target | sed -r "/^FLAG$/s/.+/$str/"

しかしこれでは上手くいかない。
というのも、どうもsedは置換後の文字列($str)が複数行だと上手く置換してくれずにエラーを吐いてしまう

sed: -e expression #1, char 28: unterminated `s' command

つまり$strが複数行で無ければいい。

解説2/3

sourceの内容は複数行なのに$strは複数行ではいけない。
矛盾しているようだが、次のsedの仕様を使えばいける。

$ cat target | sed -r '/^FLAG$/s/.+/hogehoge hugahuga\nhogahoga hugehuge/'
AAAAAA
BBBBBB
CCCCCC
hogehoge hugahuga
hogahoga hugehuge
DDDDDD
EEEEEE

つまり改行文字\nは有効なのである。

従って、sourceの内容を1行に変換しつつ、元の改行位置に\nを入れた$strを用意すればOK

解説3/3

複数行を1行にまとめる方法に関しては、固定行数であればいくつかあるが任意の行数となるとなかなか難しい。今回は次の方法を採った。

$ cat source | while IFS= read -r line ; do echo -n "$line" ; done
hogehoge hugahugahogahoga hugehuge

つまりwhile readで行ごとに読み込み、echo -nで各行を改行なしで出力している。
IFS=-rに関しては、デフォルトだと先頭・末端のスペースやバックスラッシュを取り除くwhile readの仕様対策。

あとは、1行にまとめる前に各行の末端に改行文字\nを入れておけばOK(エスケープする必要はあるが)

0
0
2

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
0
0