¿Cómo eliminar el espacio en blanco final de todos los archivos de forma recursiva?

122

¿Cómo puede eliminar todo el espacio en blanco final de un proyecto completo? Comenzando en un directorio raíz y eliminando el espacio en blanco final de todos los archivos en todas las carpetas.

Además, quiero poder modificar el archivo directamente, y no solo imprimir todo en stdout.

iamjwc
fuente
¿Está buscando una solución "portátil" o más específica para el sistema operativo? ¿Qué sistema operativo estás usando?
Joe Pineda
3
Me encantaría ver una versión de esto que funcione en OS X Snow Leopard e ignore las carpetas .git y .svn.
Trevor Turk

Respuestas:

83

Aquí hay una solución OS X> = 10.6 Snow Leopard.

Ignora las carpetas .git y .svn y sus contenidos. Además, no dejará un archivo de copia de seguridad.

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:]]*$//"
pozo profundo
fuente
10
Puede hacerlo más rápido usando en \+lugar de *en la cadena de reemplazo; de lo contrario, coincide en cada línea.
l0b0
10
Puede usar [[: blank:]] para eliminar pestañas y espacios.
Leif Gruenwoldt
21
En Mountain Lion esto vuelve sed: RE error: illegal byte sequencepara mí.
Bryson
12
Para aquellos de ustedes que tienen problemas con la "secuencia de bytes ilegal": ingrese export LANG=Ce intente nuevamente
Georg Ledermann
3
En OS X 10.9 también necesitaba lo export LC_CTYPE=C que se encuentra aquí: stackoverflow.com/questions/19242275/…
kissgyorgy
31

Utilizar:

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

si no desea que se generen los archivos ".bak":

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

como usuario de zsh, puede omitir la llamada para buscar y, en su lugar, usar:

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

Nota: Para evitar la destrucción de .gitdirectorio, trate de añadir: -not -iwholename '*.git*'.

Segundo
fuente
37
No intente esto en un repositorio de git, ya que puede dañar el almacenamiento interno de git.
mgold
11
@mgold Demasiado tarde, grrr; /
kenorb
3
Para aclarar, está bien ejecutar esto dentro de una subcarpeta de un repositorio de git, solo que no dentro de ninguna carpeta que contenga repositorios de git como descendientes, es decir, no dentro de ninguna carpeta que tenga .gitdirectorios, sin importar cuán profundamente anidados.
Illya Moskvin el
Combinando esta respuesta con @ deepwell para evitar problemas con git / svnfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss
1
Probablemente haya una mejor manera, pero me recuperé de destrozar un repositorio de git con esto clonando el repositorio en una carpeta separada y luego haciendo rsync -rv --exclude=.git repo/ repo2/que los cambios locales repotambién estuvieran en el (sin daños) repo2.
MatrixManAtYrService
29

Dos enfoques alternativos que también funcionan con las nuevas líneas de DOS (CR / LF) y hacen un trabajo bastante bueno para evitar archivos binarios :

Solución genérica que comprueba que el tipo MIME comienza 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)

Solución específica de repositorio de Git de Mat que utiliza la-Iopción degit grepomitir archivos que Git considera binarios:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'
l0b0
fuente
3
Así que realmente me gusta esta solución git. Realmente debería estar en la cima. Sin embargo, no quiero guardar retornos de carro. Pero prefiero esto al que combiné en 2010.
odinho - Velmont
Mi git se queja de que la expresión -e está vacía, pero funciona muy bien usando -e '. *'
muirbot
@okor En GNU, sedla opción de sufijo -ies opcional , pero en BSDsed no lo es. Es estrictamente hablando, no es necesario aquí de todos modos, así que lo eliminaré.
l0b0
24

En Bash:

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

Nota: Si está utilizando .gitrepositorio, trate de añadir: -not -iwholename '.git'.

Adam Rosenfield
fuente
Esto genera errores como este para cada archivo encontrado. sed: 1: "dir / file.txt": comando a espera \ seguido de texto
iamjwc
Reemplazando ';' con \; Deberia trabajar. (También las citas alrededor de {} no son estrictamente necesarias).
agnul
44
Para eliminar todos los espacios en blanco, no solo los espacios, debe reemplazar el carácter de espacio con [: espacio:] en su expresión regular sed.
WMR
Otra nota al margen: esto solo funciona con versiones sed> = 4, las versiones más pequeñas no admiten la edición en el lugar.
WMR
1
Esto me rompió la
cabeza
14

Esto funcionó para mí en OSX 10.5 Leopard, que no utiliza GNU sed o xargs.

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

¡Solo tenga cuidado con esto si tiene archivos que deben excluirse (lo hice)!

Puede usar -prune para ignorar ciertos directorios o archivos. Para los archivos Python en un repositorio git, puede usar algo como:

find dir -not -path '.git' -iname '*.py'
pojo
fuente
¿Alguna posibilidad de que puedas aclarar esto? Me gustaría un comando que elimine los espacios en blanco finales de todos los archivos en un directorio de forma recursiva, mientras ignora el directorio ".git". No puedo seguir tu ejemplo ...
Trevor Turk
Si está utilizando tcsh, deberá cambiar las comillas dobles a comillas simples. De lo contrario, obtendrá un "Nombre de variable ilegal". error.
Brandon Fosdick
GNU sed es similar pero haces -i.bak o --in-place = .bak, terminando con un comando completo de find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Sustitúyalo dirpor el directorio en cuestión como el nivel superior para recurrir.
David Gardner
sed -i .bak? ¿No debería ser sed -i.bak(sin el espacio)?
Ondra Žižka
9

Ack fue hecho para este tipo de tarea.

Funciona igual que grep, pero sabe que no debe descender a lugares como .svn, .git, .cvs, etc.

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

Mucho más fácil que saltar a través de aros con find / grep.

Ack está disponible a través de la mayoría de los administradores de paquetes (como ack o ack-grep ).

Es solo un programa Perl, por lo que también está disponible en una versión de un solo archivo que puede descargar y ejecutar. Ver: Instalar Ack

jbbuckley
fuente
ackes maravilloso. Lo he estado utilizando durante varios años y está disponible en casi todos los repositorios de paquetes para la mayoría de las distribuciones.
Felipe Alvarez
8

ex

Intenta usar Ex editor (parte de Vim):

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

Nota: Para la recursividad (bash4 y zsh), utilizamos una nueva opción de globalización ( **/*.*). Habilitado shopt -s globstar.

Puede agregar la siguiente función en su .bash_profile:

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

sed

Para usar sed, verifique: ¿Cómo eliminar espacios en blanco al final con sed?

find

Busque el siguiente script (por ejemplo remove_trail_spaces.sh) para eliminar espacios en blanco finales de los archivos:

#!/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

Ejecute este script desde el directorio que desea escanear. En OSX al final, eliminará todos los archivos que terminan en .bak.

O solo:

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

que es recomendado por Spring Framework Code Style .

kenorb
fuente
find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;solo elimina un espacio final en lugar de todos.
Karl Richter
6

Terminé no usando find y no creando archivos de respaldo.

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

Dependiendo de la profundidad del árbol de archivos, esta (versión más corta) puede ser suficiente para sus necesidades.

NOTA: esto también toma archivos binarios, por ejemplo.

Jesper Rønn-Jensen
fuente
Para archivos específicos: buscar. -nombre '* .rb' | xargs -I {} sed -i '' 's / [[: espacio:]] * $ // g' {}
Gautam Rege
No necesita el parámetro '' para sed; o podría estar perdiendo algo. Lo probé en todos los archivos en un directorio dado, así: sed -i 's / [[: space:]] * $ // g' util / *. M
Mircea
6

En lugar de excluir archivos, aquí hay una variación de lo anterior, las listas explícitamente blancas de los archivos, en función de la extensión del archivo, que desea eliminar, no dude en sazonar al gusto:

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:]]*$//"
ChicagoBob
fuente
Para que esto funcionara para mí, necesitaba agregar citas:-name "*.rb*"
haroldcarr
5

Terminé ejecutando esto, que es una mezcla entre pojo y la versión adams.

Limpiará tanto los espacios en blanco finales, como también otra forma de espacios en blanco finales, el retorno de carro:

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

No tocará la carpeta .git si hay una.

Editar : lo hizo un poco más seguro después del comentario, al no permitir tomar archivos con ".git" o ".svn". Pero cuidado, que va a tocar archivos binarios si tienes alguna. Use -iname "*.py" -or -iname "*.php"después -type fsi solo desea que toque, por ejemplo, archivos .py y .php.

Actualización 2 : ahora reemplaza todo tipo de espacios al final de la línea (lo que también significa pestañas)

odinho - Velmont
fuente
44
No sé lo que está sucediendo, pero esto borró por completo mi repositorio de git y alteró mis imágenes. ¡GENTE, TENGA MÁS CUIDADO QUE YO!
mattalxndr
Sí, arruinará los archivos binarios. Sin embargo, no debería tocar su repositorio de git en absoluto, ya que omite todo lo que reside dentro de una carpeta .git. Pero tal vez solo si estás en la misma carpeta.
odinho - Velmont
4

Esto funciona bien ... agregar / eliminar --incluye para tipos de archivo específicos:

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

Rubí:

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

Yo uso expresiones regulares. 4 pasos:

  1. Abra la carpeta raíz en su editor (yo uso Visual Studio Code).
  2. Toque el icono Buscar a la izquierda y habilite el modo de expresión regular.
  3. Ingrese "+ \ n" en la barra de búsqueda y "\ n" en la barra Reemplazar.
  4. Haga clic en "Reemplazar todo".

Esto elimina todos los espacios finales al final de cada línea en todos los archivos. Y puede excluir algunos archivos que no se ajustan a esta necesidad.

roedeercuco
fuente
2

1) Muchas otras respuestas usan -E. No estoy seguro de por qué, ya que esa es una opción de compatibilidad BSD no documentada .-rdebería usarse en su lugar.

2) Otras respuestas de uso -i ''. Eso debería ser solo -i(o -i''si se prefiere), porque -itiene el sufijo justo después.

3) Solución específica de 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]+$//'

El primero registra un alias git check-whitespaceque enumera los archivos con espacios en blanco al final. El segundo corre sedsobre ellos.

Solo uso en \tlugar de hacerlo, [:space:]ya que normalmente no veo pestañas verticales, formularios de alimentación y espacios no rompibles. Su medida puede variar.

Ondra Žižka
fuente
1

Esto es lo que funciona para mí (Mac OS X 10.8, GNU sed instalado por 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/' \{} \;

Se eliminaron los espacios finales, reemplaza las pestañas con espacios, reemplaza Windows CRLF con Unix \n.

Lo interesante es que tengo que ejecutar esto 3-4 veces antes de que todos los archivos se arreglen, gsedsiguiendo todas las instrucciones de limpieza .

yegor256
fuente