読者です 読者をやめる 読者になる 読者になる

😃 mattintosh note 📝

Hello Raspberry Pi!

💻 sed でタブを入力するには?

Mac OS X bash sed ShellScript

sed でタブの削除や置換をしたりする話です。

はじめに

「ターミナル上でタブを入力したい」という方

^V のあとに <tab> で入力できます。(環境によるかも)

「sed コマンドでタブを置換したい」という方

以下の方法などがあります。

# 先頭のみ
sed s/$'\t'//

# すべて => tr -d '\t' の方がおすすめ
sed s/$'\t'//g

「sed についてちょっと知っておきたいな〜」という方は記事の続きをどうぞ。

ただ、読む前にターミナルでもスクリプトでも構いませんが以下のコマンドを実行してみてください。(環境によって違うかもしれませんが)最後だけバックスラッシュが2つになってると思います。sed を使う場合これが結構重要です。

set -- \\\\ "\\\\" $'\\\\' '\\\\'
echo $@


以下で BSD sed に関して色々書いてますが、わざと sed のコマンド部分全体をクオートで括っていなかったりします。「何故そこにクオートが必要か?」を考えていただくと面白いかもしれません。

なんか偉そうに色々書いてるけど趣味で使ってるレベルなので詳しいことは書籍とか読んでみてください。

sed & awkプログラミング 改訂版 (A nutshell handbook)

sed & awkプログラミング 改訂版 (A nutshell handbook)

sed でタブ文字を置換する

きっと検索で来られた方は以下のようなコマンドを実行して「タブが消えない」もしくは「タブではなく t が消える」という人が多いと思います。

sed 's/\t//'

Mac OS X などに入っている BSD sed は echo や printf のようにスクリプト中の \t をタブには展開しません。

その理由はきっと以下のコマンドで t を削除できるから………かもしれません。

sed 'st\tttg'

\t をタブ文字として扱うかどうかはコマンドによって異なります。BSD sed は「タブ文字として扱わない」方ですが、タブ文字が使用できないわけではありません。BSD sed でタブ文字を扱う場合は予め \t を ←(タブ)として展開しておきます。テキストエディタなどでタブ文字を直接入力してもかまいませんが、タブなのかスペースなのか判別し難くなったり、テキスト整形時に変換されてしまう可能性もあるのであまりおすすめしません。

じゃあどうやって書くのか?ということになりますがここではシェルの $'\t' を使います。

以下の2つの書き方はどちらもタブ文字を削除します。上段ではマッチング部分で $'' 展開を行い、下段では sed スクリプト全体で $'' 展開を行います。これはシェルの機能であって sed の機能ではありません。*一部のシェルでは $'\t' をそのまま $'\t' として出力しますので注意してください。

sed s/$'\t'//
sed $'s/\t//'

どのようなスクリプトが sed に渡されているかは set -x で確認してみるといいです。きっとターミナルには以下のように出力されると思います。ブログ上ではスペースに見えるかもしれませんが s/ の後ろにはタブ文字が入っています。

+ sed 's/    //'

$'\t' を使ってタブ文字を取り除く際の例をいくつか書いておきます。

# 行頭のタブだけを削除
sed s/^$'\t'//

# 先頭のタブ文字だけを削除
sed s/$'\t'//

# 全てのタブ文字を削除
sed s/$'\t'//g

もし $'\t' が使えない場合は printf などに出力してもらいましょう。上段の例ではダブルクオートが必要になるかもしれません。

# コマンド置換でタブ文字を出力 (1)
sed s/"`printf '\t'`"//

# コマンド置換で sed スクリプトごと出力 (2)
sed "`printf 's/\t//'`"

# 変数による展開
tab=`printf '\t'`
sed s/${tab}//

改行文字に置換する

タブ文字の話から逸れますが「ある文字列を改行に変換したい」場合の話です。まずエラー例です。

sed s/\<br\>/$'\n'/

なぜエラーになるかは sed に渡されたスクリプトを見てみればわかります。sed は改行をコマンドの区切りにしているため上記の書き方だと2つのコマンドに分離してしまっているからです。

s/<br>/
/

正しく改行に変換するには以下のように書きます。エスケープの仕方やクオートの仕方は人それぞれですのであくまで一例です。

sed s/\<br\>/$'\\\n'/

sed に渡されるスクリプトはこうなります。バックスラッシュでつながっているので1つのコマンドとして扱ってくれます。

s/<br>/\
/

逆に「改行を置換したい」場合があるかと思いますが、これを sed でやろうとするとかなり面倒なので他のコマンドの使用をおすすめします。(Qiita に書いたような気もするけど)

その他

変数を使う

タブの話に戻ります。変数はシェルによって先に展開されるので $'\t' を使用した場合と同じです。

tab=$'\t'
sed "s/${tab}//"

クラスを使う

[:cntrl:] や、[:blank:]、[:space:] などを使うことで制御文字や空白を取り除くことができます。「タブ文字だけ」というのには向いていませんが s/[ ]// ←(スペースとタブ)と書くよりはわかりやすいかなと思います。

sed "s/[[:cntrl:]]//"

IFS から部分文字列展開でタブだけ取り出す

bash ではシェルの IFS 環境変数には <スペース><タブ><改行> が格納されているので部分文字列展開でタブだけを使用することができます。シェルによってはこの展開は使えませんし、IFS も一定ではないので危険です。これはただのネタですので忘れてください。

sed "s/${IFS:1:1}//"

tr を使う

用途によっては sed よりもずっとシンプルです。

tr -d '\t'

sed はシェルスクリプトやターミナル上で使おうとするとクオートやバックスラッシュなどのせいで難しくなります。まずは sed スクリプトを別で作成して練習してみるのがいいと思います。ターミナルからは -f オプションでコマンドファイルを指定できます。ヒアドキュメントで fd から読むこともできたりします。

sed -f command.sed

  • 2014å¹´06月20日に記事修正

入門bash 第3版

入門bash 第3版

bashクックブック

bashクックブック