Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

sedコマンドで文字列を改行に置換する、しかもスマートに置換する。

More than 1 year has passed since last update.

概要

  1. sedコマンドで任意の文字列を改行に置換する方法
  2. 知ってはいるけど記述が汚いのでもっと綺麗に書きたい。

そもそも改行ってどーやるの?

例えば、\nって書いてあるところを全部本物の改行に置換したいならこーやります。

nl.sh
echo "hogehoge\nfoo\nbar" | sed 's/\\n/\
/g'

sedの置換コマンド後半部分に、エスケープ用のバックスラッシュと、実際の改行コードを書くわけです。
でもこれって汚い!コマンドの途中で改行されちゃうのはイヤんな感じ。

スマートにいきましょ。

綺麗に書きたければ改行文字をシェル変数に入れておき、実際の改行を書く代わりに使えばいいのです。つまり、シェル変数$LFなどを作ってそこに'\'と'<0x0A>'の2文字を格納し、これを使えばいいのです。

まずは$LFに'\'と'<0x0A>'を入れましょ。

が!素直にはシェル変数には入ってくれません。

一筋縄ではいかない。

printfコマンドを使うとキーボードから打てないコントロール文字も生成できます。(ただし、printfは8進数で指定してくださいね。そうしないとLinux以外でエラーになります) だから'\'と'<0x0A>'の2文字分ということで、

makelf_bad.sh
LF=$(printf '\\\012')

と書くと……、2文字目に指定した改行コードが$LFに入りません。理由は、文字列の最後に改行コードがあると、シェル変数に入る前にカットされてしまうからです。じゃあどうするか???

こうやるといい

だから、シェル変数に入れる時には最後の文字を改行にしなければいいのです。そして、入った後でトリミングするという寸法です。

makelf_good.sh
LF=$(printf '\\\012_')
LF=${LF%_}

2行目の%は右からのトリミング。右の'_'をトリミングせよという意味です。これでめでたく$LFには'\'と'<0x0A>'が入りました。

これでよーやく、スマートにイケます。

$LFを作るところからまとめて正解を書きます。sedで$LFを使う時は、置換コマンドを前半と末尾に分解し(=シングルクォーテーションで切り)、その間に"$LF"(ダブルクォーテーションも含む)を挿しこめばいいのです。

nl2.sh
LF=$(printf '\\\012_')
LF=${LF%_}

echo "hogehoge\nfoo\nbar" | sed 's/\\n/'"$LF"'/g'

理屈を覚えるのはちょっと複雑ですが、覚えてしまえば綺麗なシェルスクリプトが書けます。

richmikan@github
困った時はすぐQiitaを始めとしたTipsを表面的に鵜呑みにし、使えそうなプロダクトを拾ってきてマニュアル通りに対応するプロダクト至上主義者達よ。そんなことでは、想定外の事態に見舞われた時すぐ死ぬぞ。想定外とは、マニュアルには載ってないから想定外なのだ。マニュアル通りにしか動けぬ者は、典型的なコンビニ店員の如く薄給に喘ぐだけ。頭を使え!UNIX哲学に目覚めよ!そしてPOSIX原理主義を崇拝せよ!
https://github.com/ShellShoccar-jpn
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away