Come rimuovere gli spazi vuoti finali di tutti i file in modo ricorsivo?


122

Come puoi rimuovere tutti gli spazi bianchi finali di un intero progetto? Partendo da una directory principale e rimuovendo lo spazio vuoto finale da tutti i file in tutte le cartelle.

Inoltre, voglio essere in grado di modificare il file direttamente e non solo stampare tutto su stdout.


Oh, stai cercando una soluzione "portatile" o più specifica per il sistema operativo? Che sistema operativo stai usando?
Joe Pineda,

3
Mi piacerebbe vedere una versione di questo che funziona su OS X Snow Leopard e ignora le cartelle .git e .svn.
Trevor Turk

Risposte:


83

Ecco una soluzione OS X> = 10.6 Snow Leopard.

Ignora le cartelle .git e .svn e il loro contenuto. Inoltre non lascerà un file di backup.

export LC_CTYPE=C
export LANG=C
find . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"

10
Puoi renderlo più veloce usando \+invece che *nella stringa di sostituzione - altrimenti corrisponde su ogni singola riga.
l0b0

10
Puoi usare [[: blank:]] per rimuovere sia le tabulazioni che gli spazi.
Leif Gruenwoldt

21
In Mountain Lion questo ritorna sed: RE error: illegal byte sequenceper me.
Bryson

12
Per quelli di voi che hanno problemi con la "sequenza di byte illegale": entrare export LANG=Ce riprovare
Georg Ledermann

3
In OS X 10.9 Ho anche bisogno export LC_CTYPE=C come si trova qui: stackoverflow.com/questions/19242275/...
kissgyorgy

31

Uso:

find . -type f -print0 | xargs -0 perl -pi.bak -e 's/ +$//'

se non vuoi che i file ".bak" vengano generati:

find . -type f -print0 | xargs -0 perl -pi -e 's/ +$//'

come utente zsh, puoi omettere la chiamata per trovare e invece utilizzare:

perl -pi -e 's/ +$//' **/*

Nota: per evitare la distruzione .gitdi directory, prova ad aggiungere: -not -iwholename '*.git*'.


37
Non provarlo in un repository git, poiché può danneggiare la memoria interna di git.
mgold

11
@mgold Too late, grrr; /
kenorb

3
Per chiarire, va bene eseguirlo all'interno di una sottocartella di un repository git, ma non all'interno di cartelle che contengono repository git come discendenti, ovvero non all'interno di cartelle che hanno .gitdirectory, non importa quanto profondamente annidate.
Illya Moskvin,

Combinando questa risposta con @ deepwell's per evitare problemi con git / svnfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss

1
Probabilmente c'è un modo migliore, ma mi sono ripreso dalla manipolazione di un repository git con questo clonando il repository in una cartella separata e quindi facendo rsync -rv --exclude=.git repo/ repo2/dopo di che le modifiche locali repoerano anche in (non danneggiato) repo2.
MatrixManAtYrService

29

Due approcci alternativi che funzionano anche con i newline DOS (CR / LF) e fanno un buon lavoro nell'evitare i file binari :

Soluzione generica che verifica che il tipo MIME inizi con text/:

while IFS= read -r -d '' -u 9
do
    if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
    then
        sed -i 's/[ \t]\+\(\r\?\)$/\1/' -- "$REPLY"
    else
        echo "Skipping $REPLY" >&2
    fi
done 9< <(find . -type f -print0)

Soluzione specifica per il repository Git di Mat che utilizza l'-Iopzione digit grepsaltare i file che Git considera binari:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'

3
Quindi mi piace molto questa soluzione git. Dovrebbe essere davvero in cima. Tuttavia, non voglio salvare i ritorni a capo. Ma preferisco questa a quella che ho combinato nel 2010.
odinho - Velmont

Il mio git si lamenta del fatto che l'espressione -e è vuota, ma funziona benissimo usando -e '. *'
muirbot

@okor In GNU sedl'opzione del suffisso a -iè facoltativa , ma in BSDsed non lo è. In senso stretto non è comunque necessario qui, quindi lo rimuoverò.
l0b0

24

In Bash:

find dir -type f -exec sed -i 's/ *$//' '{}' ';'

Nota: Se si sta utilizzando .gitrepository, prova ad aggiungere: -not -iwholename '.git'.


Questo genera errori come questo per ogni file trovato. sed: 1: "dir / file.txt": comando
previsto

Sostituzione di ";" con \; dovrebbe funzionare. (Anche le virgolette intorno a {} non sono strettamente necessarie).
agnul

4
Per rimuovere tutti gli spazi, non solo gli spazi, dovresti sostituire il carattere spazio con [: space:] nella tua espressione regolare sed.
WMR

Un'altra nota a margine: funziona solo con le versioni sed> = 4, le versioni più piccole non supportano la modifica sul posto.
WMR

1
Questo mi ha rotto il
culo

14

Questo ha funzionato per me in OSX 10.5 Leopard, che non utilizza GNU sed o xargs.

find dir -type f -print0 | xargs -0 sed -i.bak -E "s/[[:space:]]*$//"

Fai solo attenzione se hai file che devono essere esclusi (l'ho fatto)!

Puoi usare -prune per ignorare determinate directory o file. Per i file Python in un repository git, potresti usare qualcosa come:

find dir -not -path '.git' -iname '*.py'

Qualche possibilità che potresti chiarire questo? Vorrei un comando che rimuovesse gli spazi vuoti finali da tutti i file in una directory in modo ricorsivo, ignorando la directory ".git". Non riesco a seguire il tuo esempio ...
Trevor Turk

Se stai usando tcsh dovrai cambiare le virgolette doppie in virgolette singole. Altrimenti, otterrai un "Nome variabile illegale". errore.
Brandon Fosdick

GNU sed è simile ma fai -i.bak o --in-place = .bak, finendo con un comando completo di find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Sostituisci dircon la directory in questione come primo livello da cui ricorrere.
David Gardner

sed -i .bak? Non dovrebbe essere sed -i.bak(senza lo spazio)?
Ondra Žižka

9

Ack è stato creato per questo tipo di attività.

Funziona proprio come grep, ma sa di non scendere in posti come .svn, .git, .cvs, ecc.

ack --print0 -l '[ \t]+$' | xargs -0 -n1 perl -pi -e 's/[ \t]+$//'

Molto più facile che saltare attraverso i cerchi con find / grep.

Ack è disponibile tramite la maggior parte dei gestori di pacchetti (come ack o ack-grep ).

È solo un programma Perl, quindi è disponibile anche in una versione a file singolo che puoi semplicemente scaricare ed eseguire. Vedi: Ack Install


ackè meraviglioso. Lo uso da diversi anni ed è disponibile in quasi tutti i repository di pacchetti per la maggior parte delle distribuzioni.
Felipe Alvarez

8

ex

Prova a usare Ex editor (parte di Vim):

$ ex +'bufdo!%s/\s\+$//e' -cxa **/*.*

Nota: per la ricorsione (bash4 e zsh), utilizziamo una nuova opzione di globbing ( **/*.*). Abilita da shopt -s globstar.

Puoi aggiungere la seguente funzione nel tuo .bash_profile:

# Strip trailing whitespaces.
# Usage: trim *.*
# See: https://stackoverflow.com/q/10711051/55075
trim() {
  ex +'bufdo!%s/\s\+$//e' -cxa $*
}

sed

Per l'utilizzo sed, controlla: Come rimuovere gli spazi vuoti finali con sed?

find

Trova il seguente script (ad es. remove_trail_spaces.sh) Per rimuovere gli spazi vuoti finali dai file:

#!/bin/sh
# Script to remove trailing whitespace of all files recursively
# See: /programming/149057/how-to-remove-trailing-whitespace-of-all-files-recursively

case "$OSTYPE" in
  darwin*) # OSX 10.5 Leopard, which does not use GNU sed or xargs.
    find . -type f -not -iwholename '*.git*' -print0  | xargs -0 sed -i .bak -E "s/[[:space:]]*$//"
    find . -type f -name \*.bak -print0 | xargs -0 rm -v
    ;;
  *)
    find . -type f -not -iwholename '*.git*' -print0 | xargs -0 perl -pi -e 's/ +$//'
esac

Esegui questo script dalla directory che desideri scansionare. Su OSX, alla fine, rimuoverà tutti i file che terminano con .bak.

O semplicemente:

find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;

metodo consigliato da Spring Framework Code Style .


find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;rimuove solo uno spazio finale invece di tutto.
Karl Richter

6

Ho finito per non usare Trova e non creare file di backup.

sed -i '' 's/[[:space:]]*$//g' **/*.*

A seconda della profondità dell'albero dei file, questa (versione più breve) potrebbe essere sufficiente per le tue esigenze.

NOTA questo accetta anche file binari, per esempio.


Per file specifici: trova. -name '* .rb' | xargs -I {} sed -i '' 's / [[: space:]] * $ // g' {}
Gautam Rege

Non è necessario il parametro "" per sed; o potrei perdere qualcosa. L'ho provato su tutti i file in una determinata directory, in questo modo: sed -i 's / [[: space:]] * $ // g' util / *. M
Mircea

6

Invece di escludere i file, ecco una variazione delle precedenti liste bianche esplicite dei file, in base all'estensione del file, che vuoi rimuovere, sentiti libero di condire a piacere:

find . \( -name *.rb -or -name *.html -or -name *.js -or -name *.coffee -or \
-name *.css -or -name *.scss -or -name *.erb -or -name *.yml -or -name *.ru \) \
-print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"

Affinché questo funzionasse per me, dovevo aggiungere delle citazioni:-name "*.rb*"
haroldcarr

5

Ho finito per eseguire questo, che è un mix tra la versione Pojo e quella di Adams.

Pulirà sia gli spazi vuoti finali, sia un'altra forma di spazi bianchi finali, il ritorno a capo:

find . -not \( -name .svn -prune -o -name .git -prune \) -type f \
  -exec sed -i 's/[:space:]+$//' \{} \;  \
  -exec sed -i 's/\r\n$/\n/' \{} \;

Non toccherà la cartella .git se ce n'è una.

Modifica : reso un po 'più sicuro dopo il commento, non consentendo di prendere file con ".git" o ".svn". Ma attenzione, si tocca i file binari se hai un po '. Usa -iname "*.py" -or -iname "*.php"dopo-type f se vuoi che tocchi solo i file .py e .php.

Aggiornamento 2 : ora sostituisce tutti i tipi di spazi alla fine della riga (che significa anche schede)


4
Non so cosa stia succedendo, ma questo ha completamente rovinato il mio repository git e ha incasinato le mie immagini. PERSONE, STATE PIÙ ATTENTI DI ME!
mattalxndr

Sì, rovinerà i file binari. Tuttavia, non dovrebbe toccare affatto il tuo repository git, perché salta tutto ciò che risiede all'interno di una cartella .git. Ma forse solo se ti trovi nella stessa cartella.
odinho - Velmont

4

Funziona bene .. aggiungi / rimuovi --include per tipi di file specifici:

egrep -rl ' $' --include *.c *  | xargs sed -i 's/\s\+$//g'

4

Rubino:

irb
Dir['lib/**/*.rb'].each{|f| x = File.read(f); File.write(f, x.gsub(/[ \t]+$/,"")) }

3

Uso le espressioni regolari. 4 passaggi:

  1. Apri la cartella principale nel tuo editor (io uso Visual Studio Code).
  2. Tocca l'icona Cerca a sinistra e abilita la modalità espressione regolare.
  3. Immettere "+ \ n" nella barra di ricerca e "\ n" nella barra di sostituzione.
  4. Fare clic su "Sostituisci tutto".

Ciò rimuove tutti gli spazi finali alla fine di ogni riga in tutti i file. E puoi escludere alcuni file che non soddisfano questa esigenza.


2

1) Molte altre risposte usano -E. Non sono sicuro del perché, poiché è un'opzione di compatibilità BSD non documentata .-rdovrebbe essere usato invece.

2) Altre risposte usano -i ''. Dovrebbe essere giusto -i(o -i''se preferito), perché -iha il suffisso subito dopo.

3) Soluzione specifica per Git:

git config --global alias.check-whitespace \
'git diff-tree --check $(git hash-object -t tree /dev/null) HEAD'

git check-whitespace | grep trailing | cut -d: -f1 | uniq -u -z | xargs -0 sed --in-place -e 's/[ \t]+$//'

Il primo registra un alias git check-whitespaceche elenca i file con spazi vuoti finali. Il secondo gira sedsu di loro.

Uso solo \tpiuttosto che [:space:]come in genere non vedo schede verticali, feed di moduli e spazi non divisibili. La tua misura può variare.


1

Questo è ciò che funziona per me (Mac OS X 10.8, GNU sed installato da Homebrew):

find . -path ./vendor -prune -o \
  \( -name '*.java' -o -name '*.xml' -o -name '*.css' \) \
  -exec gsed -i -E 's/\t/    /' \{} \; \
  -exec gsed -i -E 's/[[:space:]]*$//' \{} \; \
  -exec gsed -i -E 's/\r\n/\n/' \{} \;

Rimossi gli spazi finali, sostituisce le tabulazioni con spazi, sostituisce Windows CRLF con Unix \n.

La cosa interessante è che devo eseguirlo 3-4 volte prima che tutti i file vengano corretti, secondo tutte le gsedistruzioni di pulizia .

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.