it-swarm.com.de

Einfaches Sed-Ersetzen von Tabs, die auf mysteriöse Weise versagen

Das sollte eigentlich einfach sein, aber aus irgendeinem Grund funktioniert es nicht:

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

Anstatt Tabulatorzeichen zu ersetzen, werden t Zeichen ersetzt. Ich habe jede erdenkliche Variation ausprobiert, mit Zitaten gespielt usw. Ich habe gegoogelt und festgestellt, dass alle anderen ziemlich ähnliche Ausdrücke verwendet haben und sie scheinen für sie zu funktionieren.

Das -E ist eine OS X-Sache. Ich dachte, der Fehler könnte auf eine seltsame Eigenart von OS Xs sed zurückzuführen sein, also habe ich es auch mit Ruby) versucht (ohne das -i) und bekam das gleiche Ergebnis:

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

Ich verwende Bash 3.2.51 unter OS X und iTerm, obwohl ich nicht sehen kann, wie schrecklich diese sein könnten. Ich habe keine seltsamen Umgebungsvariablen festgelegt, obwohl ich alle veröffentlichen kann, die Sie für relevant halten.

Was könnte falsch sein?

[~ # ~] update [~ # ~]: Ich muss einen anderen Fehler oder Tippfehler gemacht haben, als ich versuchte die Ruby Version, da Gilles darauf hinweist, dass es tut funktioniert (und ich habe nie ihn mich steuern lassen falsch!). Ich bin mir nicht sicher, was passiert ist, aber ich bin mir ziemlich sicher, dass es mein Fehler gewesen sein muss.

46
iconoclast

Die Syntax \t Für ein Tabulatorzeichen in sed ist nicht Standard. Diese Flucht ist eine GNU sed Erweiterung . Sie finden viele Beispiele online, die es verwenden, weil viele Leute GNU sed (es ist die sed-Implementierung unter nicht eingebettetem Linux) verwenden. Aber OS X sed unterstützt wie andere * BSD sed \t nicht für tab und behandelt stattdessen \t als Backslash, gefolgt von t.

Es gibt viele Lösungen, wie zum Beispiel:

  • Verwenden Sie ein wörtliches Tabulatorzeichen.

    sed -i.bak 's/  /  /' file.txt
    
  • Verwenden Sie tr oder printf, um ein Tabulatorzeichen zu erstellen.

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • Verwenden Sie bashs String-Syntax, die Backslash-Escapezeichen ermöglicht .

    sed -i.bak $'s/\t/  /' file.txt
    
  • Verwenden Sie Perl, Python oder Ruby. Das von Ihnen veröffentlichte Snippet Ruby=) funktioniert.

Verwenden Sie ein Bash-spezifisches in Anführungszeichen , mit dem Sie Zeichenfolgen wie in C verwenden können, sodass ein echtes Tabulatorzeichen an sed übergeben wird, keine Escape-Sequenz:

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

funktioniert für mich unter OS X und ist der gleiche Befehl, den ich unter Linux ständig benutze.

3
user193377

Wie bereits erwähnt, unterstützen nicht alle sed-Implementierungen die Notation von \t als horizontale Registerkarte.

Sie können Ihre Substitution leicht erreichen mit:

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

Dadurch wird eine In-situ-Ersetzung durchgeführt, bei der Ihre Originaldatei als "* .old" erhalten bleibt. Perl erlaubt alternative Trennzeichen für das klassische / den Ausdruck viel lesbarer machen (d. h. ohne das "Leaning Toothpick" -Syndrom).

Das + sagt, dass eine oder mehrere Wiederholungen eines Tabulatorzeichens ersetzt werden sollen. Der Modifikator g ermöglicht globale Ersetzungen am Ende jeder Zeile.

1
JRFerguson

Wenn es in Ordnung ist, bash oder zsh als Shell zu benötigen, ist dies die einfachste Lösung, die ich mir vorstellen kann:

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

Beachten Sie jedoch, dass echo Flags (-n und -e) sind in POSIX undefiniert, sodass eine POSIX-konforme Shell diese Flags nicht verstehen muss, viele jedoch aus Kompatibilitätsgründen.

0
Mecki

Sie können auch echo in sed verwenden:

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

0
saulR

Wenn Sie ein leistungsfähigeres sed wünschen (unterstützt \t und mehr) als unter OS X, installiere GNU sed .

0
vinc17