Conversione di schede in spazi in molti file


11

Ho un sacco di file con schede disseminate dappertutto e mi piacerebbe convertirle tutte in spazi. Conosco il expandcomando, ma sfortunatamente dovrei scrivere ogni singolo file che lo utilizza. C'è un modo più semplice per farlo su Linux?

Risposte:


12

Prova quanto segue:

find ./ -type f -exec sed -i 's/\t/ /g' {} \;

Se vuoi quattro spazi, prova:

find ./ -type f -exec sed -i 's/\t/    /g' {} \;

Ciò sostituirà ogni scheda con un singolo spazio. Poiché la persona menzionata usa expand, presumo che desideri preservare l'allineamento del testo.
garyjohn,

Devi 's/\t/ /g'sostituire più di una scheda per riga.
Daniel Andersson,

1
Un notevole aumento di velocità se ci sono molti file sta facendo " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (cioè " +" invece di " \;"), se la findversione lo supporta (e non ho incontrato personalmente nessuna versione che non lo fa, ma non è uno standard POSIX , quindi suppongo che potrebbe accadere su alcuni sistemi. Vedi " -exec command {} +" nel manuale). Invece di lanciare un'istanza di sedper ogni file, questo creerà un elenco di argomenti con tutti gli argomenti dei nomi file che il sistema supporta ( getconf ARG_MAX= 2097152 sul mio sistema), proprio come xargs, e quindi avvia molti meno sedprocessi.
Daniel Andersson,

6
Nota per tutti gli utenti Mac che lo trovano: la versione di OS X di sednon comprende la \tsequenza di escape della scheda. Puoi sostituirlo con un carattere di tabulazione letterale, che puoi inserire nella shell [Ctrl]+V, [Tab].
Jeremy Banks,

expandè probabilmente meglio che sedper questo, come spiegato in: stackoverflow.com/a/11094620/131824
David Weinraub

6

Ci sono molti modi per farlo. Ci sono anche molti modi per spararti al piede mentre lo fai se non stai attento o se sei nuovo su Linux come sembri. Supponendo che sia possibile creare un elenco di file che si desidera convertire, utilizzando qualcosa di simile findo manualmente con un editor, è sufficiente reindirizzare tale elenco nel seguente.

while read file
do
   expand "$file" > /tmp/expandtmp
   mv /tmp/expandtmp "$file"
done

Un modo in cui puoi spararti ai piedi è quello di fare un refuso in modo da finire un file vuoto su tutti i nomi di file che specifichi, eliminando così il contenuto di tutti i tuoi file. Quindi fai attenzione e prova tutto quello che fai prima su un piccolo set di file di cui hai eseguito il backup.


3
Rendere la mvcondizione che il successo di expand:expand ... && mv ...
in pausa fino a nuovo avviso.

Non dimenticare expand -t 4di espandere le schede in 4 spazi. Inoltre, questo metodo può creare nuove righe finali. Ma altrimenti funziona.
mgold

3
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo crea una variabile modello foo per ogni riga di input, in modo da poter fare riferimento all'input più di una volta.

-print0e -0dire a entrambi i comandi di usare \ 0 come separatore di riga anziché SPACE, quindi questo comando funziona per i percorsi con spazi.


1
find -name \*.js -exec bash -c 'expand -t 4 "$0" | tee "$0"' {} \;

Contro: i
file più grandi della dimensione del buffer della pipe ( 64 KB ) vengono troncati

Pro:
nessun file temporaneo di dimensioni
maggiori del buffer del tubo viene troncato


0

Questo è meglio:

find . -name *.java ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

3
Perché è meglio? Non è una grande idea da usare /tmp/eperché se qualcos'altro sta usando quel file, questo lo rovinerà. Come se due utenti volessero utilizzarlo contemporaneamente.
Kevin Panko

0

Ho provato a risolvere questo problema tenendo presenti i seguenti requisiti:

  • Filtra i file in base al loro nome, per elaborare ad esempio solo file .cpp o .json
  • Supporta l'elaborazione parallela. Nel caso in cui ci siano molti file, questo può fornire un enorme accelerazione
  • La soluzione dovrebbe adattarsi a una riga per un facile utilizzo

L'ultimo requisito è stato il più difficile da soddisfare perché "espandi" non consente di modificare i file in atto.

Ho trovato la seguente soluzione:

find . -type f -regextype egrep -regex '.*\.(c|cpp|h|hpp)'  -print0 | xargs -0 -n 1 -P 10 -IFILE bash -c ' ( echo "Processing FILE..." && expand -t 4 "FILE" > /tmp/expand.$$ && mv /tmp/expand.$$ "FILE" ) || exit 255'

Ecco qualche spiegazione:

  • "trova" trova i file da elaborare. "-regextype egrep" consente di filtrarli in base al loro nome e ad un'espressione regolare nel formato "egrep"
  • il parametro "-type f" assicura che abbineremo solo i file normali, non ad esempio le directory o qualsiasi altra cosa speciale
  • il parametro "-regexp" è l'espressione regolare stessa, che in questo caso corrisponde a qualsiasi file che termina con .c, .cpp, .h o .hpp (l'intero nome deve corrispondere, quindi "file.c2" non lo farebbe , che è quello che vogliamo)
  • "-print0" indica a "find" di stampare i percorsi dei file sul suo output standard con il carattere 0 alla fine di ogni percorso. Insieme all'opzione "-0" per "xargs", consente di passare nomi contenenti carrelli di ritorno da uno strumento all'altro (anche se è una situazione piuttosto rara ...)
  • xargs avvia un nuovo processo per ogni percorso ("-n 1"), ma potrebbe eseguire fino a 10 processi in parallelo ("-P 10")
  • xargs usa l'alias "FILE" per passare ogni percorso di file al comando, che è uno script bash
  • lo script bash chiama "espandi" e salva il risultato in un file temporaneo i cui nomi contengono l'ID del processo corrente ($$), in modo che tutti i processi eseguiti in parallelo in un dato file utilizzino file temporanei diversi
  • l'intero comando utilizza il modello (comando1 && comando2 && comando3) in modo che il processo si interrompa se un sottocomando restituisce un errore
  • se c'è qualche errore dalla precedente catena "&&", lo script bash restituirà un codice di uscita 255 che causerà l'arresto immediato di xargs
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.