不可解に失敗するタブの単純なsed置換


44

これは本当に簡単なはずですが、何らかの理由で機能していません。

sed -i.bak -E 's/\t/  /' file.txt

タブ文字を置き換える代わりに、文字を置き換えますt。私は、引用で遊んで、私は考えることができ、この上のすべてのバリエーションを試してみましたなどIましGoogleで検索して見つけた誰もが、かなり類似した表現を使用して、彼らは彼らのために仕事に思えます。

これ-EはOS Xのものです。失敗はOS Xの奇妙な癖の結果かもしれないと思ったsedので、Rubyでも試してみて(なしで-i)、同じ結果を得ました:

ruby -pe '$_.gsub!(/\t/,"  ")' < file.txt > file.new

OS XとiTermでBash 3.2.51を使用していますが、これらのどれがひどく関連するかはわかりません。奇妙な環境変数は設定していませんが、関連があると思われるものは投稿できます。

何が間違っているのでしょうか?

更新:Rubyバージョンを試してみたときに、Gillesがそれ機能することを指摘しているため、他の間違いやタイプミスを犯したに違いありません(そして、私は彼に間違った方向を向かわせたことがありません!)何が起こったのかはわかりませんが、それは間違いだったに違いありません。


5
ステートメントの\tinを、tabキーとcontrolキーを一緒に押した場所に置き換えてみてください。sedCTRL-V<TAB><TAB>CTRL-Vv
unxnut

ルビーも間違った答えを得ている場合、それはあなたの正規表現ライブラリかもしれません。(私は両方のコマンドをテストし、両方ともタブを2つのスペースに置き換えました。)そうすれば、Gnu sedをインストールすると、正しいライブラリもインストールされることを願っています。
ctrl-alt-delor 14

回答:


64

\tsedのタブ文字の構文は標準ではありません。そのエスケープはGNU sed拡張機能です。多くの人がGNU sed(非組み込みLinuxでのsedの実装)を使用しているため、オンラインで多くの例を使用しています。ただし、OS X sedは、他の* BSD sedと同様に\t、タブをサポートせず、代わりに\tバックスラッシュが続くことを意味するものとして扱いますt

次のような多くのソリューションがあります。

  • リテラルのタブ文字を使用します。

    sed -i.bak 's/  /  /' file.txt
    
  • trまたはprintfを使用して、タブ文字を作成します。

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • バックスラッシュエスケープを許可するbashの文字列構文を使用します

    sed -i.bak $'s/\t/  /' file.txt
    
  • Perl、Python、またはRubyを使用します。投稿したRubyスニペットは機能します。


スクリプトに含まれるsedスクリプト...sed-fオプションを介して使用される)の場合、リテラルのタブ文字が唯一の可能性に思えます。vimでこれを編集するときset noexpandtabは重要です。
トバイアス

警告:同僚があなたの後ろに戻り、後でスクリプトを壊したい場合にのみ、その「リテラルタブ文字」テクニックを使用してください。tr同僚がスクリプトを読むときに顔を刺すようにしたい場合にのみ、この手法を使用してください。
ブルーノブロノスキー

コードの2番目のブロックで2番目の二重引用符が間違って配置されていますか?私はそれを現在の単一引用符の位置に移動しなければなりませんでした。
エレンスペルタス

bash文字列構文へのリンクをお寄せいただきありがとうございます...私は考えもしていませんでした(そしてこれが最良のオプションです、私見)。
レビグローカー

sed $'s/<regex>/\t/' file.txt挿入のために動作$しますが、置換に正規表現の一部を含めようとするとスクリプトが壊れるようです。つまりsed $'s,\(ontology/[0-9]\+\),\t\txxx\1xxx\t\t,'、「xxxxxx」に予想される一致値を「」で置き換えます。\1bashの文字列構文を使用する場合と同等のものはありますか?編集:xxx <U + 231C> xxxの中央にU + 231Cユニコード文字が想定されています。
ジョシュ

14

Cのような文字列を使用できるようにするBash固有の引用符を使用して、実際のタブ文字がエスケープシーケンスではなくsedに渡されるようにします。

sed -i.bak -E $'s/\t/  /' file.txt

1
「ANSI-C」とも呼ばれ、他の人がそれについてさらに情報を調べたい場合に引用します。
ウィスバッキー

2
どのbourneシェルでも動作するようで、非bash UNIXでも動作します。ただし、csh-variantsでは機能しません。
-jornane

3
sed -i $'s/\t/  /g' file.txt 

OS Xで動作し、Linuxで常に使用するコマンドと同じです。


これは、すべての行のすべてのタブを置き換えるのに対して、OPは最初のタブ(使用するコマンドから判断)のみを置き換えることを意図していることに注意してください。
クサラナナンダ

1

前述のように、すべてのsed実装\tが水平タブとしての表記をサポートしているわけではありません。

簡単に置換を実現できます:

 perl -pi.old -e 's{\t+}{ }g' file.txt

これにより、元のファイルを「* .old」として保存するin situ置換が実行されます。Perlでは、クラシックの代替デリミタを使用し/て、式をより読みやすくします(つまり、「つまようじ」症候群がありません)。

+タブ文字の1回以上の繰り返しを交換することになっていると言います。g修飾子は、各行の終わりを通じてグローバルな交換を可能にします。


0

echoinsideを使用することもできますsed

sed -i "s/$(echo '\t')//g"


の一部のシェルの実装でecho '\t'出力\tされることに注意してくださいecho
クサラナナンダ

0

OS Xのものより強力なsed(サポート\tなど)が必要な場合は、GNU sedをインストールしてください。


Rubyでも動作しなかったため、OS X sedが問題であると結論付けた理由がわかりません。それが問題だと信じる理由はありますか?GNU sedをインストールして問題を解決できると信じる理由があれば喜んでインストールしますが、それをほとんど除外したようです。
iconoclast 14

:ルビーを使用すると、唯一のバックスラッシュを使用する必要がありますruby -pe '$_.gsub!(/\t/," ")' < file.txt
vinc17

0

シェルとして要求するbashzsh、シェルとして問題ない場合、これは私が考えることができる最も簡単なソリューションです:

sed "s/$(echo -n -e "\t")/ /" file.txt

ただし、echoフラグ(-nおよび-e)はPOSIXでは未定義であるため、POSIX準拠のシェルではこれらのフラグを理解する必要はありませんが、多くの場合、互換性の理由からそうなります。


-1

私は誰も非常に簡単な解決策を提案しなかったことに驚いていsed -i.bak -E 's/\\\t/ /' file.txt ます: それはトリックをするはずです。

すべてが置き換えられたときに正規表現で\ t文字を使用しようとしていることをsedが理解できるようにするには、エスケープをエスケープする必要があります(3つの\ s)。


特に3つのバックスラッシュが必要なのはなぜですか?
マイケルホーマー

3
私はGNUを使用している場合sed、1は\ 何のエスケープ処理が必要でないよう、十分です。問題は、BSD sedがタブのこの構文をサポートしていないことです。
iconoclast

私のエルキャピタンでは動作しません。
フランクリンゆう

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.