web-dev-qa-db-ja.com

不思議なことにタブの単純なsed交換が失敗する

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

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

タブ文字を置き換える代わりに、t文字を置き換えます。私はこれについて考えられるすべてのバリエーションを試してみました。引用などで遊んでみました。Googleで見つけた 他のすべての人 と非常によく似た式を使用していて、それらはうまく機能しているようです。

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

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

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

何が悪いのでしょうか?

[〜#〜] update [〜#〜]:他の間違いをしたか、 Rubyバージョンを試したときのタイプミス。Gillesはそれがは動作すると(そして私は彼に私を間違って操らせた!)何が起こったのかはわかりませんが、それは私の間違いだったに違いありません。

46
iconoclast

Sedのタブ文字の構文\tは標準ではありません。そのエスケープは 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スニペットは機能します。

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

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

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

3
user193377

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

あなたは簡単にあなたの代わりを達成することができます:

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

これにより、元のファイルを「* .old」として保持するin-situ置換が実行されます。 Perlでは、従来の/の代替区切り文字を使用して、式をより読みやすくすることができます(つまり、「つまようじを傾ける」症候群がありません)。

+は、タブ文字の1つ以上の繰り返しが置換されることを示しています。 g修飾子は、各行の終わり全体でグローバル置換を有効にします。

1
JRFerguson

bashまたはzshをシェルとして要求しても問題ない場合、これは私が考えることができる最も簡単な解決策です。

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

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

0
Mecki

echo内でsedを使用することもできます。

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

0
saulR

より強力なsedが必要な場合(サポート\t以上)OS Xの場合よりも、 GNU sed をインストールします。

0
vinc17