Semplice sostituzione sed di schede misteriosamente fallite


44

Questo dovrebbe essere davvero semplice, ma per qualche motivo non funziona:

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

Invece di sostituire i caratteri di tabulazione, sostituisce i tcaratteri. Ho provato tutte le varianti che mi sono venute in mente, giocando con le citazioni, ecc. Ho cercato su Google e ho trovato tutti gli altri usando espressioni abbastanza simili e sembrano funzionare per loro.

La -Eè una cosa OS X. Ho pensato che l'errore potesse essere il risultato di una strana stranezza di OS X sed, quindi l'ho provato anche con Ruby (senza -i) e ho ottenuto lo stesso risultato:

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

Sto usando Bash 3.2.51 su OS X e iTerm, anche se non riesco a vedere come nessuno di questi possa essere terribilmente rilevante. Non ho impostato nessuna strana variabile d'ambiente, anche se posso pubblicare quelle che ritieni possano essere rilevanti.

Cosa potrebbe esserci di sbagliato?

UPDATE : Devo aver fatto qualche altro errore o typo quando ho provato la versione di Ruby, poiché Gilles sottolinea che fa il lavoro (e non ho mai avuto di lui guidare me sbagliato!). Non sono sicuro di cosa sia successo, ma sono abbastanza sicuro che deve essere stato un mio errore.


5
Può essere che si dovrebbe cercare di sostituire l' \tnella seddichiarazione con CTRL-V<TAB>cui <TAB>è il tasto tab e CTRL-Vè la chiave di controllo e vpremuti insieme.
Unxnut,

se anche ruby ​​sta ottenendo una risposta sbagliata, allora potrebbe essere la tua libreria regexp. (Ho testato entrambi i tuoi comandi, ed entrambi sostituisco la scheda con 2 spazi.) Quindi spero che se installi Gnu sed installerà anche la libreria corretta.
ctrl-alt-delor,

Risposte:


64

La sintassi \tper un carattere di tabulazione in sed non è standard. Quella fuga è un'estensione sed GNU . Trovi molti esempi online che lo usano perché molte persone usano GNU sed (è l'implementazione di sed su Linux non incorporato). Ma OS X sed , come altri * BSD sed, non supporta la \ttabulazione e invece considera \tla barra rovesciata seguita da t.

Esistono molte soluzioni, come:

  • Usa un carattere di tabulazione letterale.

    sed -i.bak 's/  /  /' file.txt
    
  • Utilizzare tro printfper produrre un carattere di tabulazione.

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • Usa la sintassi delle stringhe di bash che consente di uscire da backslash .

    sed -i.bak $'s/\t/  /' file.txt
    
  • Usa Perl, Python o Ruby. Lo snippet di Ruby che hai pubblicato funziona.


Per gli script sed che sono contenuti in uno ...sedscript (usato tramite -fopzione), i caratteri di tabulazione letterali mi sembrano l'unica possibilità. Quando si modifica questo con VIM, set noexpandtabè importante.
Tobias,

Avvertenza: usa la tecnica del "carattere letterale tab" solo se vuoi che il tuo collega torni indietro e rompa la sceneggiatura in seguito. Usa questa trtecnica solo se vuoi che il tuo collega ti pugni in faccia quando leggono la tua sceneggiatura.
Bruno Bronosky,

Il secondo segno di virgolette doppie è posizionato male nel secondo blocco di codice? Ho dovuto spostarlo dove si trova attualmente la virgoletta singola di chiusura.
Ellen Spertus,

Grazie per il collegamento alla sintassi della stringa bash ... Non ne avevo idea (e questa è l'opzione migliore, IMHO).
levigroker,

sed $'s/<regex>/\t/' file.txtfunziona per l'inserimento, ma $sembra che rompa il mio script quando provo a includere parte della regex nella mia sostituzione, cioè sed $'s,\(ontology/[0-9]\+\),\t\txxx\1xxx\t\t,'dà `xxxxxx` con il mio valore di corrispondenza previsto sostituito da ``. Esiste un equivalente a \1quando si utilizza la sintassi della stringa di bash? Modifica: si suppone che il carattere unicode U + 231C sia nel mezzo di xxx <U + 231C> xxx.
Josh,

14

Utilizzare una specifica Bash citando che consente di utilizzare le stringhe come in C, in modo che un carattere di tabulazione vero e proprio è passato a sed, non una sequenza di escape:

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

1
Chiamato anche "ANSI-C" citando se gli altri vogliono cercare maggiori informazioni a riguardo.
wisbucky,

2
Sembra funzionare su qualsiasi shell bourne, funziona anche su UNIX non bash. Tuttavia, non funziona con le varianti csh.
jornane,

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

funziona per me su OS X ed è lo stesso comando che uso sempre su Linux.


Si noti che questo sostituisce tutte le schede su ogni riga mentre l'OP intende sostituire solo il primo (a giudicare dal comando che usano).
Kusalananda

1

Come notato, non tutte le sedimplementazioni supportano la notazione di \tcome una scheda orizzontale.

Puoi facilmente ottenere la tua sostituzione con:

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

Ciò esegue una sostituzione in situ che conserva il file originale come "* .old". Perl consente delimitatori alternativi per il classico /rendendo l'espressione molto più leggibile (cioè priva della sindrome dello "stecchino pendente").

La +dice uno o più ripetizioni di un carattere di tabulazione devono essere sostituiti. Il gmodificatore consente sostituzioni globali per tutta la fine di ogni riga.


0

Puoi anche usare echodentro sed:

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


Si noti che echo '\t'verrà appena prodotto \tnell'implementazione di alcune shell echo.
Kusalananda

0

Se vuoi una versione più potente sed(supportante \te più) di quella su OS X, installa GNU sed .


Dato che non ha funzionato neanche con Ruby, non sono sicuro del motivo per cui concluderei che sedil problema sia l' OS X. Hai un motivo per credere che sia questo il problema? Sarei felice di installare GNU sed se avessi motivo di credere che avrebbe risolto il problema, ma sembra che lo abbia praticamente escluso.
iconoclasta,

Con Ruby dovrai usare solo una barra rovesciata:ruby -pe '$_.gsub!(/\t/," ")' < file.txt
vinc17,

0

Se va bene richiedere basho zshcome shell, questa è la soluzione più semplice che mi viene in mente:

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

Si noti tuttavia che i echoflag ( -ne -e) non sono definiti in POSIX, quindi una shell conforme a POSIX non richiede di capire questi flag, ma molti lo faranno per motivi di compatibilità.


-1

Sono sorpreso che nessuno abbia suggerito la soluzione molto semplice di: sed -i.bak -E 's/\\\t/ /' file.txt dovrebbe fare il trucco.

Devi fuggire dalla fuga (da qui i 3 \) per consentire a sed di capire che stai cercando di usare un carattere \ t nell'espressione regolare quando tutto viene sostituito ...


Perché tre barre rovesciate in particolare?
Michael Homer,

3
Se uso GNU sed, uno \ è sufficiente, poiché non è necessario scappare. Il problema è che BSD sednon supporta questa sintassi per le schede.
iconoclasta il

Non funziona sul mio El Capitan.
Franklin Yu,

-4

Questo ha funzionato per me.

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


3
Questo perché usi GNU sed. Questo non è ciò che utilizza l'OP.
Kusalananda
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.