Como remover o espaço em branco à direita de todos os arquivos recursivamente?

122

Como você pode remover todo o espaço em branco à direita de um projeto inteiro? Iniciando em um diretório raiz e removendo o espaço em branco à direita de todos os arquivos em todas as pastas.

Além disso, quero poder modificar o arquivo diretamente, e não apenas imprimir tudo no stdout.

iamjwc
fonte
Ah, você está procurando uma solução "portátil" ou mais específica para o sistema operacional? Qual sistema operacional você está usando?
Joe Pineda
3
Adoraria ver uma versão disso que funcionaria no OS X Snow Leopard e ignoraria as pastas .git e .svn.
Trevor Turk

Respostas:

83

Aqui está uma solução para o OS X> = 10.6 Snow Leopard.

Ignora as pastas .git e .svn e seu conteúdo. Também não deixará um arquivo de 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:]]*$//"
deepwell
fonte
10
Você pode torná-lo mais rápido usando em \+vez de *na sequência de substituição - caso contrário, ele corresponderá em cada linha.
L0b0
10
Você pode usar [[: blank:]] para remover guias e espaços.
Leif Gruenwoldt 13/03/12
21
No Mountain Lion isso retorna sed: RE error: illegal byte sequencepara mim.
Bryson
12
Para aqueles de você ter problemas com "seqüência de byte ilegal": Entre export LANG=Ce tente novamente
Georg Ledermann
3
No OS X 10.9, eu também precisava, export LC_CTYPE=C como encontrado aqui: stackoverflow.com/questions/19242275/…
kissgyorgy
31

Usar:

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

se você não deseja que os arquivos ".bak" sejam gerados:

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

como usuário zsh, você pode omitir a chamada para localizar e, em vez disso, usar:

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

Nota: Para evitar destruir .gitdiretório, tente adicionar: -not -iwholename '*.git*'.

Sec
fonte
37
Não tente fazer isso em um repositório git, pois isso pode corromper o armazenamento interno do git.
MGold
11
@mgold Tarde demais, grrr; /
kenorb
3
Para esclarecer, é bom executá-lo dentro de uma subpasta de um repositório git, apenas não dentro de pastas que contenham repositórios git como descendentes, ou seja, não dentro de pastas que tenham .gitdiretórios, não importa quão profundamente aninhado.
Illya Moskvin
Combinando esta resposta com @ deepwell é para evitar git / svn questõesfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss
1
Provavelmente existe uma maneira melhor, mas eu me recuperei de manipular um repositório git com isso, clonando o repositório em uma pasta separada e depois fazendo o rsync -rv --exclude=.git repo/ repo2/que as alterações locais repotambém estavam no (sem danos) repo2.
MatrixManAtYrService
29

Duas abordagens alternativas que também funcionam com as novas linhas do DOS (CR / LF) e fazem um bom trabalho para evitar arquivos binários :

Solução genérica que verifica se o tipo MIME começa com 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)

Solução específica do repositório Git da Mat, que usa a-Iopção degit greppular arquivos que o Git considera binários:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'
l0b0
fonte
3
Então, eu realmente gosto dessa solução git. Realmente deveria estar no topo. Eu não quero salvar retornos de carro, no entanto. Mas eu prefiro este ao que eu combinado em 2010.
odinho - Velmont
Meu git reclama que a expressão -e está vazio, mas ele funciona muito bem usando -e '*.'
muirbot
@okor No GNU, seda opção de sufixo -ié opcional , mas no BSDsed não é. Estritamente falando, não é necessário aqui de qualquer maneira, então vou removê-lo.
L0b0 /
24

No Bash:

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

Nota: Se você estiver usando .gitrepositório, tente adicionar: -not -iwholename '.git'.

Adam Rosenfield
fonte
Isso gera erros como este para cada arquivo encontrado. sed: 1: "dir / file.txt": comando a espera \ seguido de texto
iamjwc
Substituindo ';' com \; Deveria trabalhar. (Também não são estritamente necessárias aspas em torno de {}).
Agnul 29/09/08
4
Para remover todos os espaços em branco e não apenas os espaços, substitua o caractere de espaço por [: space:] na sua expressão regular sed.
WMR
Outra observação lateral: isso funciona apenas com versões sed> = 4, versões menores não suportam edição no local.
WMR 30/09/08
1
Isso quebrou meu git :(
CrabMan
14

Isso funcionou para mim no OSX 10.5 Leopard, que não usa GNU sed ou xargs.

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

Apenas tenha cuidado com isso se você tiver arquivos que precisam ser excluídos (eu fiz)!

Você pode usar -une para ignorar determinados diretórios ou arquivos. Para arquivos Python em um repositório git, você pode usar algo como:

find dir -not -path '.git' -iname '*.py'
pojo
fonte
Alguma chance de você esclarecer isso? Eu gostaria de um comando que remova espaço em branco à direita de todos os arquivos em um diretório recursivamente, ignorando o diretório ".git". Eu não consigo seguir o seu exemplo ...
Trevor Turk
Se você estiver usando o tcsh, precisará alterar as aspas duplas para aspas simples. Caso contrário, você receberá um "Nome de variável ilegal". erro.
Brandon Fosdick 29/05
O GNU sed é semelhante, mas você faz -i.bak ou --in-place = .bak, terminando com um comando completo de find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Substitua dirpelo diretório em questão como o nível superior de onde recorrer.
David Gardner
sed -i .bak? Não deveria ser sed -i.bak(sem espaço)?
Ondra Žižka
9

A confirmação foi feita para esse tipo de tarefa.

Funciona como grep, mas sabe que não desce para lugares como .svn, .git, .cvs, etc.

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

Muito mais fácil do que saltar por aros com o find / grep.

O ack está disponível na maioria dos gerenciadores de pacotes (como ack ou ack-grep ).

É apenas um programa Perl, por isso também está disponível em uma versão de arquivo único que você pode apenas baixar e executar. Consulte: Instalação Ack

jbbuckley
fonte
acké maravilhoso. Utiliza-o há vários anos e está disponível em quase todos os repositórios de pacotes para a maioria das distribuições.
Felipe Alvarez
8

ex

Tente usar o editor Ex (parte do Vim):

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

Nota: Para recursão (bash4 e zsh), usamos uma nova opção de globbing ( **/*.*). Ativar por shopt -s globstar.

Você pode adicionar a seguinte função ao seu .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: Como remover os espaços em branco à direita com o sed?

find

Localize o seguinte script (por exemplo remove_trail_spaces.sh) para remover os espaços em branco finais dos arquivos:

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

Execute esse script no diretório que você deseja verificar. No OSX no final, ele removerá todos os arquivos que terminam com .bak.

Ou apenas:

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

recomendado pelo Spring Framework Code Style .

kenorb
fonte
find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;remove apenas um espaço à direita em vez de todos.
Karl Richter
6

Acabei não usando find e não criando arquivos de backup.

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

Dependendo da profundidade da árvore de arquivos, isso (versão mais curta) pode ser suficiente para suas necessidades.

NOTA: isso também leva arquivos binários, por exemplo.

Jesper Rønn-Jensen
fonte
Para arquivos específicos: encontre. -name '* .rb' | xargs -I {} sed -i '' 's / [[: space:]] * $ // g' {}
Gautam Rege
Você não precisa do parâmetro '' para sed; ou eu posso estar perdendo alguma coisa. Eu tentei em todos os arquivos em um determinado diretório, assim: sed -i 's / [[: space:]] * $ // g' util / *. M
Mircea
6

Em vez de excluir arquivos, aqui está uma variação das listas brancas explicitamente acima, com base na extensão do arquivo que você deseja remover, sinta-se à vontade para temperar a gosto:

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
fonte
Para que isso funcione para mim, eu precisava adicionar aspas:-name "*.rb*"
haroldcarr
5

Acabei executando isso, que é uma mistura entre a versão pojo e adams.

Ele limpará o espaço em branco à direita e também outra forma de espaço em branco à direita, o 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/' \{} \;

Não tocará na pasta .git se houver uma.

Edit : Tornou um pouco mais seguro após o comentário, não permitindo levar arquivos com ".git" ou ".svn". Mas cuidado, ele vai tocar arquivos binários, se você tem algum. Use -iname "*.py" -or -iname "*.php"after -type fse quiser apenas tocar em, por exemplo, arquivos .py e .php.

Atualização 2 : agora substitui todos os tipos de espaços no final da linha (o que significa guias também)

odinho - Velmont
fonte
4
Não sei o que está acontecendo, mas isso confundiu totalmente meu repositório git e mexeu com minhas imagens. PESSOAS, TENHA MAIS CUIDADO DO QUE EU ESTAVA!
mattalxndr
Sim, isso arruinará arquivos binários. No entanto, ele não deve tocar no seu repositório git, porque ignora o que estiver dentro de uma pasta .git. Mas talvez apenas se você estiver na mesma pasta.
Odinho - Velmont 25/05
4

Isso funciona bem. Adicione / remova --include para tipos de arquivos específicos:

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

Rubi:

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

Eu uso expressões regulares. 4 passos:

  1. Abra a pasta raiz no seu editor (eu uso o Visual Studio Code).
  2. Toque no ícone Pesquisar à esquerda e ative o modo de expressão regular.
  3. Digite "+ \ n" na barra de pesquisa e "\ n" na barra de substituição.
  4. Clique em "Substituir tudo".

Isso remove todos os espaços finais no final de cada linha em todos os arquivos. E você pode excluir alguns arquivos que não se encaixam nessa necessidade.

roedeercuco
fonte
2

1) Muitas outras respostas são usadas -E. Não sei por que, como essa é a opção de compatibilidade com BSD não documentada . -rdeve ser usado em seu lugar.

2) Outras respostas são usadas -i ''. Isso deve ser justo -i(ou -i''se preferido), porque -item o sufixo logo depois.

3) Solução específica 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]+$//'

O primeiro registra um alias do git check-whitespaceque lista os arquivos com espaços em branco à direita. O segundo é executado sedsobre eles.

Eu só uso, \te não [:space:]como normalmente não vejo guias verticais, feeds de formulário e espaços que não podem ser quebrados. Sua medida pode variar.

Ondra Žižka
fonte
1

Isto é o que funciona para mim (Mac OS X 10.8, GNU sed instalado pelo 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/' \{} \;

Os espaços à direita removidos, substituem as guias por espaços, substituem o Windows CRLF pelo Unix \n.

O interessante é que eu tenho que executar isso 3-4 vezes antes que todos os arquivos sejam corrigidos, com todas as gsedinstruções de limpeza .

yegor256
fonte