ubuntuで連続したハイフン文字だけを置換削除するコマンド 単独ハイフンは残したいバージョン

こんにちは、minoruです。

ubuntuでテキストファイル内の余分な飾り文字として68個並んだハイフン「-」を削除したいなぁと思って作業してたんですが、GUIのテキストエディタで簡単に実現できるんですが、テキストファイルとは言えファイルサイズが巨大になると置換や一括削除に時間がかかります。

滅多に無いパターンの作業かも知れませんが、滅多に無いからこそわからなくて困りました。特に通常の数字やアルファベットなら簡単そうなんですが、ハイフンという記号なので「¥」とか「\」などのエスケープで少々頭が混乱します。

終わってみれば何でも無い事なんですが、一応備忘録とビギナーの方の参考になればと書き残しておきたいと思います。

私がハイフンを置換・削除しようとしていたテキストファイルは以下のような感じ。

Surper Mario Bros.
--------------------------------------------------------------------
1-1 1up mushroom is there.
1-2 1up mushroom is there.
1-3 1up mushroom is none.
1-4 1up mushroom is none.

そう、2行目の68個並んだハイフンがいらないのです。

はっきり言ってgeditとかBluefishなどの置換機能で簡単に取り除けるのですが、今回はテキストファイルと言えども結構ファイルサイズが大きかったわけですよ。そこでちょっとでも軽くしたいと思ってコマンドでどうにかしたいと思い至りました。

連続したハイフンだけを置換削除する方法

結論から言うと以下の通りです。

cat ./置換前ファイル名 | sed -e 's/-\{2,\}//g' > ./置換後ファイル名

ハイフンにはエスケープ文字は不要。2つ以上ハイフンが続く場合を示す{2,}の{}がエスケープが必要って事ですね。ちなみに3つから6まで…などとしたい場合は \{3,6\} こんな感じで表現すればOKです。

今回の場合は飾り区切りとして使われているハイフンは68個並んでいますから、 \{68\} と書いてもOKですし、偶数なので実は「’s/–//g’」これでもOKなんですよ。単独ハイフンだけが残りますよね。

置換条件を囲っているシングルクォーテーションはダブルクォーテーションでも大丈夫なんですが、ダブルクォーテーションで囲った場合は「$」「`」「\」などがあると挙動が変わってしまいます。

例えばシェルスクリプトを使って置換の際に変数を使おうとする場合はダブルクォーテーションで囲まないとダメです。シングルクォーテーションでは変数の中身では無く、変数そのままの見た目上の文字として扱います。

なので普通にテキストの置換ならシングルクォーテーションが良いのでは無いかと思います。

ちなみに「s/」は正規表現で置換を行う事を表していて、sのあとは#などでも構わないようです。置換する文の中に「/」自身が含まれているような場合には「#」などを使えば良いみたいですね。「sの後に使った記号が区切り文字」として機能するようです。

そ して「//g」ですが、//の間に何も入れなければ削除、たとえば「/hoge/g」と入れていれば条件に一致した文を「hoge」に置換します。最後の 「g」を省略すると1行の中に複数回一致があっても最初の1回しか置換しませんので、通常は付けておいた方が良いですね。

ubuntuでsedを使って改行を別の文字に置換するコマンド

sedコマンドで置換するのは慣れれば便利だし、難しくも無いのですが、改行の取り扱いに関してはどうにもこうにもなかなか言う事を聞いてくれません。結局ubuntuのデフォルトの環境では以下のようにするしか無さそうな感じです。

sed -e ':loop; N; $!b loop; s/\n/置換する文字/g'

ちなみにコマンドを途中で改行して…という手法もあるようですが、私の環境では上手くいきませんでした。通常の文字を改行に置換する場合は普通に’s/hoge/\n/g’で置換できました。

1文字だけの置換だとダメ

私が最初に間違ってしまったのは tr という「1文字だけ置換するコマンド」を使ってしまった事で、trが1文字しか扱えない事を知らず、随分時間を無駄にしてしまいました。

ちなみに tr でも、ファイル内に半角スペースが1個だったり、2個連続だったり、5個連続だったりと無数にある場合、それを「n個の連続したスペースを1個のタブ文字に置換する」というテクニックがあります。

まず、何個連続しているかわからないが、ファイル内の全ての「スペースの連続」を1つのスペースに置換します。trの後に付け加えている「-s」というのが、同じ連続した文字を1文字に置き換えるという意味です。

cat ./置換前ファイル名 | tr -s ' ' > ./置換後ファイル名

これで連続したスペースが全て「1個のスペース」に置換されますので、例えばそのスペースをタブ文字に変換したいなーという時は、そのあとスペースをタブ文字に置換します。

cat ./置換前ファイル名 | tr ' ' '\t' > ./置換後ファイル名

このように2段階に分けてやります。

いえね、最初sedで1回で済ませようと思ったんですが…

cat ./置換前ファイル名 | sed -e 's/ +/\t/g' > ./置換後ファイル名

あれれ?全然置換されてない…。そう、「 +」というのが「スペースが1個以上並んでいたらそれを1つの塊として扱ってくれという意味なんですけど、この+の前に「¥」とか「\」などのエスケープ文字が必要なんですよ!

cat ./置換前ファイル名 | sed -e 's/ \+/\t/g' > ./置換後ファイル名

私は最初ハイフンにもエスケープ文字を付けたりして、このエスケープ文字を使わないといけない所、使ってはいけない所、この判断が混乱してしまっていたわけですね。はい。

  • このエントリーをはてなブックマークに追加