Remplacement simple des onglets par un échec mystérieux


44

Cela devrait être vraiment simple, mais pour une raison quelconque, cela ne fonctionne pas:

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

Au lieu de remplacer les caractères de tabulation, il remplace les tcaractères. J'ai essayé toutes les variantes de ce que je pouvais penser, jouer avec citation, etc. J'ai googlé et trouvé tout le monde en utilisant des expressions assez similaires et ils semblent travailler pour eux.

Le -Eest une chose d'OS X. Je pensais que l'échec pouvait être le résultat d'une bizarrerie bizarre d'OS X sed, alors je l'ai essayé aussi avec Ruby (sans le -i) et j'ai obtenu le même résultat:

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

J'utilise Bash 3.2.51 sur OS X et iTerm, bien que je ne vois pas en quoi ces applications pourraient être terriblement pertinentes. Je n'ai pas défini de variables d'environnement étranges, bien que je puisse en publier toutes celles que vous jugez pertinentes.

Quel pourrait être le problème?

Mise à jour : Je dois avoir fait une autre erreur oufautefrappe quand j'ai essayé la version Ruby, puisque Gilles souligne qu'il fait le travail (et jeai jamais lui avait me diriger mal!). Je ne suis pas sûr de ce qui s'est passé, mais je suis à peu près sûr que ce doit être mon erreur.


5
Peut-être devriez-vous essayer de remplacer le \tdans la seddéclaration par CTRL-V<TAB>où se <TAB>trouve la touche de tabulation et la CTRL-Vtouche de contrôle venfoncée.
unxnut

si ruby ​​obtient également une mauvaise réponse, il pourrait s'agir de votre bibliothèque regexp. (J'ai testé vos deux commandes, et toutes deux remplacent l'onglet par 2 espaces.) J'espère donc que si vous installez Gnu sed, il installera également la bonne bibliothèque.
ctrl-alt-delor

Réponses:


64

La syntaxe \td'un caractère de tabulation dans sed n'est pas standard. Cet échappement est une extension GNU sed . Vous trouvez beaucoup d'exemples en ligne qui l'utilisent parce que beaucoup de gens utilisent GNU sed (c'est l'implémentation de sed sur Linux non embarqué). Mais OS X sed , comme les autres * BSD sed, ne prend pas en charge les \ttabulations et considère plutôt \tcomme une barre oblique inverse suivie de t.

Il existe de nombreuses solutions, telles que:

  • Utilisez un caractère de tabulation littéral.

    sed -i.bak 's/  /  /' file.txt
    
  • Utilisez trou printfpour produire un caractère de tabulation.

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • Utilisez la syntaxe de chaîne de bash permettant les échappements avec barre oblique inversée .

    sed -i.bak $'s/\t/  /' file.txt
    
  • Utilisez Perl, Python ou Ruby. L'extrait de Ruby que vous avez posté fonctionne.


Pour les scripts sed contenus dans un ...sedscript (utilisé via l' -foption), les caractères de tabulation littéraux me semblent la seule possibilité. Lors de l'édition avec vim, set noexpandtabc'est important.
Tobias

Avertissement: Utilisez cette technique de "caractère de tabulation littérale" uniquement si vous souhaitez que votre collègue revienne derrière vous et rompt votre script ultérieurement. Utilisez cette trtechnique uniquement si vous voulez que votre collègue vous poignarde au visage quand il lit votre script.
Bruno Bronosky

Le deuxième guillemet double est-il mal placé dans le deuxième bloc de code? Je devais le déplacer là où se trouve actuellement la citation simple.
Ellen Spertus

Merci pour le lien vers la syntaxe de chaîne bash ... Je n'en avais aucune idée (et c'est la meilleure option, à mon humble avis).
Levigroker

sed $'s/<regex>/\t/' file.txtfonctionne pour l'insertion, mais cela $semble rompre mon script lorsque j'essaie d'inclure une partie de l'expression rationnelle dans ma substitution, c'est-à-dire qu'il sed $'s,\(ontology/[0-9]\+\),\t\txxx\1xxx\t\t,'donne `xxxxxx` avec la valeur de correspondance attendue remplacée par ``. Y at-il un équivalent à \1utiliser la syntaxe de chaîne de bash? Edit: il est supposé que le caractère unicode U + 231C se trouve au milieu du xxx <U + 231C> xxx.
Josh

14

Utilisez une citation spécifique à Bash qui vous permet d'utiliser des chaînes comme en C, de sorte qu'un véritable caractère de tabulation soit passé à sed, et non une séquence d'échappement:

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

1
Également appelée "ANSI-C", elle indique si d'autres personnes veulent rechercher plus d'informations à ce sujet.
Wisbucky

2
Semble fonctionner sur n'importe quel shell bourne, fonctionne également sur les UNIX non basiques. Ne fonctionne pas sur csh-variantes cependant.
Jornane

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

fonctionne pour moi sur OS X et est la même commande que je utilise sur Linux tout le temps.


Notez que cela remplace tous les onglets de chaque ligne, alors que l'OP a l'intention de ne remplacer que le premier (à en juger par la commande utilisée).
Kusalananda

1

Comme indiqué, toutes les sedimplémentations ne prennent pas en charge la notation \tsous forme d'onglet horizontal.

Vous pouvez facilement réaliser votre substitution avec:

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

Ceci effectue un remplacement in situ qui conserve votre fichier d'origine en tant que "* .old". Perl autorise des délimiteurs alternatifs pour le classique, /rendant l'expression beaucoup plus lisible (c'est-à-dire dépourvue du syndrome du "cure-dent penché").

Le +dit une ou plusieurs répétitions d'un caractère de tabulation doivent être remplacées. Le gmodificateur permet les remplacements globaux à la fin de chaque ligne.


0

Vous pouvez également utiliser à l' echointérieur sed:

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


Notez que cela echo '\t'sortira \tdans l'implémentation de certains shells echo.
Kusalananda

0

Si vous voulez un logiciel plus puissant sed(supportant \tet plus) que celui sur OS X, installez GNU sed .


Etant donné que cela n’a pas fonctionné avec Ruby non plus, je ne suis pas sûr de savoir pourquoi je conclurais que sedle problème est celui d’OS X. Avez-vous une raison de croire que c'est le problème? Je serais ravi d’installer GNU sed si j’avais des raisons de penser que cela résoudrait le problème, mais il semble que j’ai à peu près exclu cela.
iconoclast

Avec Ruby, vous devrez utiliser une seule barre oblique inverse:ruby -pe '$_.gsub!(/\t/," ")' < file.txt
vinc17

0

S'il est correct d'exiger bashou en zshtant que shell, c'est la solution la plus simple à laquelle je puisse penser:

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

Notez cependant que les echodrapeaux ( -net -e) ne sont pas définis dans POSIX, aussi un shell conforme à POSIX ne nécessite-t-il pas de comprendre ces drapeaux, mais beaucoup le feront pour des raisons de compatibilité.


-1

Je suis surpris que personne n'ait suggéré la solution très simple de: sed -i.bak -E 's/\\\t/ /' file.txt Cela devrait faire l'affaire.

Vous devez échapper à l'échappement (d'où les 3 \ s) pour permettre à sed de comprendre que vous essayez d'utiliser un caractère \ t dans l'expression régulière lorsque tout est substitué ...


Pourquoi trois antislashs spécifiquement?
Michael Homer

3
Si j'utilise GNU sed, un seul \ suffit car aucune évasion n'est nécessaire. Le problème est que BSD sedne prend pas en charge cette syntaxe pour les onglets.
iconoclaste le

Ne fonctionne pas sur mon El Capitan.
Franklin Yu

-4

Cela a fonctionné pour moi.

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


3
C'est parce que vous utilisez GNU sed. Ce n'est pas ce que l'OP utilise.
Kusalananda
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.