Einfaches Auswechseln von Tabs, die auf mysteriöse Weise versagen

43

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

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

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

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

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

Ich verwende Bash 3.2.51 unter OS X und iTerm, obwohl ich nicht sehe, wie all das fürchterlich relevant sein könnte. 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 begangen haben, als ich die Ruby-Version ausprobiert habe, da Gilles darauf hinweist, dass es funktioniert (und er hat mich nie falsch gelenkt!). Ich bin mir nicht sicher, was passiert ist, aber ich bin mir ziemlich sicher, dass es mein Fehler gewesen sein muss.

Bilderstürmer
quelle
5
Kann sein , sollten Sie die ersetzen versuchen , \tin der sedmit Anweisung , CTRL-V<TAB>wo <TAB>die Tab - Taste und CTRL-VStrg - Taste ist und vzusammengedrückt wird .
Unxnut
Wenn Ruby auch eine falsche Antwort erhält, könnte dies Ihre reguläre Ausdrucksbibliothek sein. (Ich habe beide Befehle getestet und beide Tabulatoren durch zwei Leerzeichen ersetzt.) Wenn Sie Gnu sed installieren, wird hoffentlich auch die richtige Bibliothek installiert.
Strg-Alt-Delor

Antworten:

64

Die Syntax \tfü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 verwenden (es ist die sed-Implementierung auf nicht eingebettetem Linux). Aber OS X sed unterstützt , wie andere * BSD sed, keine \tTabulatoren und behandelt diese stattdessen \tals Backslash gefolgt von t.

Es gibt viele Lösungen, wie zum Beispiel:

  • Verwenden Sie ein literales Tabulatorzeichen.

    sed -i.bak 's/  /  /' file.txt
    
  • Verwenden Sie troder printf, um ein Tabulatorzeichen zu erzeugen.

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • Verwenden Sie die Zeichenfolgensyntax von bash, um umgekehrte Schrägstriche zuzulassen .

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

Gilles 'SO - hör auf böse zu sein'
quelle
Für sed-Skripte, die in einem ...sedSkript enthalten sind (über -fOption verwendet), scheinen mir die literalen Tabulatorzeichen die einzige Möglichkeit zu sein. Bei der Bearbeitung mit vim set noexpandtabist dies wichtig.
Tobias
Warnung: Verwenden Sie diese "Literal Tab Character" -Technik nur, wenn Sie möchten, dass Ihr Kollege zurückkommt und Ihr Skript später bricht. trWenden Sie diese Technik nur an, wenn Ihr Kollege Ihnen beim Lesen Ihres Drehbuchs ins Gesicht stechen soll.
Bruno Bronosky
Ist das zweite Anführungszeichen im zweiten Codeblock falsch platziert? Ich musste es dorthin verschieben, wo sich derzeit das schließende einfache Anführungszeichen befindet.
Ellen Spertus
Vielen Dank für den Link zur Bash-String-Syntax ... Ich hatte keine Ahnung (und dies ist die beste Option, IMHO).
Levigroker
sed $'s/<regex>/\t/' file.txtfunktioniert zum Einfügen, aber das $scheint mein Skript zu sed $'s,\(ontology/[0-9]\+\),\t\txxx\1xxx\t\t,'beschädigen, wenn ich versuche, einen Teil des regulären Ausdrucks in meine Ersetzung aufzunehmen, dh xxxxxx, wobei mein erwarteter Übereinstimmungswert durch `` ersetzt wird. Gibt es eine Entsprechung zur \1Verwendung der Zeichenfolgensyntax von bash? Edit: Es soll das U + 231C Unicode-Zeichen in der Mitte des xxx <U + 231C> xxx geben.
Josh
14

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

sed -i.bak -E $'s/\t/  /' file.txt
Cristian Ciupitu
quelle
1
Wird auch als "ANSI-C" -Zitat bezeichnet, wenn andere mehr Informationen darüber nachschlagen möchten.
wisbucky
2
Scheint auf jeder Bourne-Shell zu funktionieren, funktioniert auch auf Nicht-Bash-UNIXen. Funktioniert allerdings nicht mit csh-Varianten.
15.
1

Wie bereits erwähnt, unterstützen nicht alle sedImplementierungen die Schreibweise \tals 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 ursprüngliche Datei als "* .old" erhalten bleibt. Perl erlaubt alternative Trennzeichen für den Klassiker, /wodurch der Ausdruck viel besser lesbar wird (dh ohne das "Leaning Toothpick" -Syndrom).

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

JRFerguson
quelle
1
sed -i $'s/\t/  /g' file.txt 

funktioniert für mich unter OS X und ist derselbe Befehl, den ich unter Linux die ganze Zeit benutze.

user193377
quelle
Beachten Sie, dass hierdurch alle Registerkarten in jeder Zeile ersetzt werden, während das OP nur die erste ersetzen soll (nach dem verwendeten Befehl zu urteilen).
Kusalananda
0

Sie können auch echodrinnen verwenden sed:

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

saulR
quelle
Beachten Sie, dass dies echo '\t'nur \tin der Implementierung einiger Shells von ausgegeben wird echo.
Kusalananda
0

Wenn Sie ein leistungsfähigeres sed(unterstützendes \tund mehr) als das unter OS X wollen, installieren Sie GNU sed .

vinc17
quelle
Da es auch mit Ruby nicht geklappt hat, bin ich mir nicht sicher, warum ich daraus schließen würde, dass OS X seddas Problem ist. Haben Sie einen Grund zu der Annahme, dass dies das Problem ist? Ich würde gerne GNU sed installieren, wenn ich Grund zur Annahme hätte, dass es das Problem lösen würde, aber anscheinend habe ich das so ziemlich ausgeschlossen.
Iconoclast
Mit Ruby müssen Sie nur einen Backslash verwenden:ruby -pe '$_.gsub!(/\t/," ")' < file.txt
vinc17
0

Wenn es in Ordnung ist, etwas anzufordern bashoder zshals Shell, dann ist dies die einfachste Lösung, die ich mir vorstellen kann:

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

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

Mecki
quelle
-1

Ich bin überrascht, dass niemand die sehr einfache Lösung vorgeschlagen hat: sed -i.bak -E 's/\\\t/ /' file.txt Das sollte den Trick machen.

Sie müssen das Escape-Zeichen (daher die 3 \ s) umgehen, damit sed versteht, dass Sie versuchen, ein \ t-Zeichen im regulären Ausdruck zu verwenden, wenn alles ersetzt wird ...

Vas
quelle
Warum speziell drei Backslashes?
Michael Homer
3
Wenn ich GNU benutze sed, reicht eins \ aus, da kein Fluchtweg nötig ist. Das Problem ist, dass BSD seddiese Syntax für Tabs nicht unterstützt.
Iconoclast
Funktioniert nicht auf meinem El Capitan.
Franklin Yu
-4

Das hat bei mir funktioniert.

sed-es / [\ t] / / g '

RChristensen
quelle
3
Dies liegt daran, dass Sie GNU verwenden sed. Dies ist nicht das, was das OP verwendet.
Kusalananda