sed

sed ファイル内の改行を削除, 連続した空白を1つにする

More than 3 years have passed since last update.


コマンド

とりあえず結論

sed -r -e ':loop;N;$!b loop;s/\n/ /g' -e 's/ +/ /g' INPUTFILE

INPUTFILE から改行を削除し、かつ連続した空白を1つに置換した結果を出力します。

例えば、


sample.txt

foo

bar
baz

を与えた場合は

foo bar baz

こうなります。

出力せずに INPUTFILE を直接上書きしてよければ -i オプションを追加します。


解説


構造

上のコマンドは次のような構造になっています。

sed + -r + -e 'スクリプト1' + -e 'スクリプト2' + 入力ファイル

複数の置換処理を行う場合は -e 'スクリプト' を複数回与えます。

以下、左から順に解説します。


拡張正規表現の有効化

-r または --regexp-extended で拡張正規表現を有効にします。

上の例で言うとスクリプト2の中にある + が拡張正規表現です。


スクリプト1:改行の削除

-e ':loop;N;$!b loop;s/\n/ /g'

-e はスクリプトを与える引数です。

中身の方は意味がわからないのでもう少しバラします。

-e ':ラベル; Nコマンド; bコマンド; 置換コマンド'



  • ; は複数のコマンドを1行で書くための区切りです。


  • :ラベルb コマンド(後述)で参照するためのラベルを定義しています。


  • N コマンドは次の行を読み込みます。


  • b コマンドは指定したラベルに分岐します(GOTOとかジャンプだと思えばOKです)。


  • $ は最終行にマッチする アドレス です。


    • コマンドの前にはアドレスを指定することができ、コマンドはアドレスにマッチした行に対してのみ働きます。

    • アドレスとコマンドの間に ! を挟むと、指定したアドレスに マッチしない場合 にコマンドを実行します。




  • :loop;N;$!b loop; をまとめると「まず loop ラベルを定義し、次の行を読み込み、最終行でなければ loop に戻る」すなわち 「最終行に到達するまで N コマンドを繰り返す」=「全行読み込む」 という意味になります。


  • s は置換コマンドです。置換の詳細は省きますが s/\n/ /g で「全ての \n を空白に置換する」となります。

以上の組み合わせで、「全行に対して置換を実行」を実現しています。


スクリプト2:連続した空白を1つにする

-e 's/ +/ /g'

これは sed 云々と言うより正規表現の話ですが、 / +/ で「1つ以上の任意数の空白」です。/ +/ だと空白が1つでもマッチするので、もし対象ファイルが超巨大な場合は / {2,}/ (2つ以上の空白)にすると少し早くなるかもしれません。


以上です。

# 全行処理についてメモっておきたいがための記事でした。