bash script Como converter conversas em espaços em todos os arquivos de um diretório?



bash script (16)

Como converter conversas em espaços em todos os arquivos de um diretório (possivelmente recursivamente)?

Além disso, existe uma maneira de definir o número de espaços por guia?


Answer #1

Eu gosto do exemplo "find" acima para o aplicativo recursivo. Para adaptá-lo para não ser recursivo, apenas alterando os arquivos no diretório atual que correspondem a um caractere curinga, a expansão do glob globular pode ser suficiente para pequenas quantidades de arquivos:

ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v

Se você quer que ele fique em silêncio depois de confiar que funciona, simplesmente solte o -v no comando sh no final.

Claro que você pode escolher qualquer conjunto de arquivos no primeiro comando. Por exemplo, liste apenas um subdiretório específico (ou diretórios) de uma maneira controlada como esta:

ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh

Ou, por sua vez, execute o find (1) com alguma combinação de parâmetros de profundidade, etc.

find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh

Answer #2

Use sed barra invertida.

No linux:

  • Substitua todas as guias por um hífen, em todos os arquivos * .txt:

    sed -i $'s/\t/-/g' *.txt
  • Substitua todas as guias por 1 espaço, em todos os arquivos * .txt:

    sed -i $'s/\t/ /g' *.txt
  • Substitua todas as guias por 4 espaços, em todos os arquivos * .txt:

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

Em um mac:

  • Substitua todas as guias por 4 espaços, em todos os arquivos * .txt:

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

Answer #3

Você pode usar o comando pr geralmente disponível (man page here ). Por exemplo, para converter guias em quatro espaços, faça o seguinte:

pr -t -e=4 file > file.expanded
  • -t suprime cabeçalhos
  • -e=num expande as guias para espaços num

Para converter todos os arquivos em uma árvore de diretórios recursivamente, ignorando arquivos binários:

#!/bin/bash
num=4
shopt -s globstar nullglob
for f in **/*; do
  [[ -f "$f" ]]   || continue # skip if not a regular file
  ! grep -qI "$f" && continue # skip binary files
  pr -t -e=$num "$f" > "$f.expanded.$$" && mv "$f.expanded.$$" "$f"
done

A lógica para pular arquivos binários é deste post .

NOTA:

  1. Fazer isso pode ser perigoso em um git ou svn repo
  2. Esta não é a solução certa se você tiver arquivos de código que tenham guias incorporadas em literais de string

Answer #4

Minha recomendação é usar:

find . -name '*.lua' -exec ex '+%s/\t/  /g' -cwq {} \;

Comentários:

  1. Use a edição no local. Mantenha backups em um VCS. Não há necessidade de produzir arquivos * .orig. É uma boa prática para diferenciar o resultado do último commit para garantir que isso funcione como esperado, em qualquer caso.
  2. sed é um editor de fluxo. Use ex para edição em vigor. Isso evita a criação de arquivos temporários extras e shells de desova para cada substituição, como na resposta principal .
  3. AVISO: Isso mexe com todas as guias, não apenas aquelas usadas para recuo. Também não faz a substituição consciente de contexto das abas. Isso foi suficiente para o meu caso de uso. Mas pode não ser aceitável para você.
  4. EDIT: Uma versão anterior desta resposta usou find|xargs vez de find -exec . Como apontado por @ gniourf-gniourf isso leva a problemas com espaços, citações e caracteres de controle em nomes de arquivos cf. Wheeler

Answer #5

Aviso: Isso irá quebrar seu repo.

Isso corromperá os arquivos binários , incluindo os que .git sob svn , .git ! Leia os comentários antes de usar!

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

O arquivo original é salvo como [filename].orig .

Desvantagens:

  • Substituirá as guias por todos os lugares em um arquivo.
  • Levará muito tempo se você tiver um dump SQL de 5 GB nesse diretório.

Answer #6

O uso da expand como sugerido em outras respostas parece a abordagem mais lógica para essa tarefa sozinha.

Dito isso, isso também pode ser feito com o Bash e o Awk, caso você queira fazer algumas outras modificações junto com ele.

Se estiver usando o Bash 4.0 ou superior, o shopstar globstar pode ser usado para pesquisar recursivamente com ** .

Com o GNU Awk versão 4.1 ou superior, sed como modificações no arquivo "inplace" podem ser feitas:

shopt -s globstar
gawk -i inplace '{gsub("\t","    ")}1' **/*.ext

Caso você queira definir o número de espaços por guia:

gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext

Answer #7

Faça o download e execute o seguinte script para converter recursivamente guias difíceis em guias simples em arquivos de texto simples.

Execute o script de dentro da pasta que contém os arquivos de texto simples.

#!/bin/bash

find . -type f -and -not -path './.git/*' -exec grep -Iq . {} \; -and -print | while read -r file; do {
    echo "Converting... "$file"";
    data=$(expand --initial -t 4 "$file");
    rm "$file";
    echo "$data" > "$file";
}; done;

Answer #8

Substituição simples com sed está bem, mas não é a melhor solução possível. Se houver espaços "extras" entre as guias, eles ainda estarão lá após a substituição, de modo que as margens ficarão irregulares. Guias expandidas no meio das linhas também não funcionarão corretamente. Na bash , podemos dizer em vez disso

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

para aplicar expand a cada arquivo Java na árvore de diretórios atual. Remova / substitua o argumento -name se você estiver segmentando alguns outros tipos de arquivo. Como um dos comentários menciona, tenha muito cuidado ao remover -name ou usando um caractere curinga fraco. Você pode facilmente destruir o repositório e outros arquivos ocultos sem intenção. É por isso que a resposta original incluiu isto:

Você deve sempre fazer uma cópia de backup da árvore antes de tentar algo assim, caso algo dê errado.


Answer #9

Use o vim-way:

$ ex +'bufdo retab' -cxa **/*.*
  • Faça o backup! antes de executar o comando acima, pois ele pode corromper seus arquivos binários.
  • Para usar globstar ( ** ) para recursão, ative por shopt -s globstar .
  • Para especificar um tipo de arquivo específico, use por exemplo: **/*.c

Para modificar a tabstop, adicione +'set ts=2' .

No entanto, o lado negativo é que ele pode substituir guias dentro das seqüências de caracteres .

Então, para uma solução ligeiramente melhor (usando substituição), tente:

$ ex -s +'bufdo %s/^\t\+/  /ge' -cxa **/*.*

Ou usando o ex editor + expand utilitário:

$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*

Para espaços à direita, consulte: Como remover espaços em branco finais de vários arquivos?

Você pode adicionar a seguinte função ao seu .bash_profile :

# Convert tabs to spaces.
# Usage: retab *.*
# See: https://.com/q/11094383/55075
retab() {
  ex +'set ts=2' +'bufdo retab' -cxa $*
}

Answer #10

Tente a ferramenta de linha de comando expand .

expand -i -t 4 input | sponge output

Onde

  • -i é usado para expandir apenas guias principais em cada linha;
  • -t 4 significa que cada guia será convertida em 4 caracteres em branco (8 por padrão).
  • sponge é do pacote moreutils e evita limpar o arquivo de entrada .

Finalmente, você pode usar o gexpand no OSX, depois de instalar o coreutils com o Homebrew ( brew install coreutils ).


Answer #11

Converter guias no espaço apenas em arquivos ".lua" [tabs -> 2 spaces]

find . -iname "*.lua" -exec sed -i "s#\t#  #g" '{}' \;

Answer #12

Você pode usar o find com o pacote tabs-to-spaces para isso.

Primeiro, instale as tabs-to-spaces

npm install -g tabs-to-spaces

em seguida, execute este comando a partir do diretório raiz do seu projeto;

find . -name '*' -exec t2s --spaces 2 {} \;

Isso substituirá todos os caracteres de tab por dois spaces em cada arquivo.


Answer #13

Para converter todos os arquivos Java recursivamente em um diretório para usar 4 espaços em vez de uma guia:

find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;

Answer #14

Pode-se usar o vim para isso:

find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;

Como Carpetsmoker afirmou, ele será retablado de acordo com as configurações do vim . E modelines nos arquivos, se houver. Além disso, ele substituirá as guias não apenas no início das linhas. Qual não é o que você geralmente quer. Por exemplo, você pode ter literais, contendo guias.


Answer #15

Método amigável do repositório Git

git-tab-to-space() (
  d="$(mktemp -d)"
  git grep --cached -Il '' | grep -E "${1:-.}" | \
    xargs -I'{}' bash -c '\
    f="${1}/f" \
    && expand -t 4 "$0" > "$f" && \
    chmod --reference="$0" "$f" && \
    mv "$f" "$0"' \
    '{}' "$d" \
  ;
  rmdir "$d"
)

Atue em todos os arquivos sob o diretório atual:

git-tab-to-space

Atua somente em arquivos C ou C ++:

git-tab-to-space '\.(c|h)(|pp)$'

Você provavelmente quer isto notavelmente por causa daqueles Makefiles irritantes que requerem abas.

O comando git grep --cached -Il '' :

  • lista apenas os arquivos rastreados, então nada dentro do .git
  • exclui diretórios, arquivos binários (seriam corrompidos) e links simbólicos (seriam convertidos em arquivos regulares)

como explicado em: Como listar todos os arquivos de texto (não binários) em um repositório git?

chmod --reference mantém as permissões de arquivo inalteradas: https://unix.stackexchange.com/questions/20645/clone-ownership-and-permissions-from-another-file Infelizmente não consigo encontrar uma alternativa POSIX sucinta .

Se sua base de código teve a idéia maluca de permitir guias brutas funcionais em strings, use:

expand -i

e então divirta-se passando por cima de todas as abas não iniciais de linha uma a uma, com as quais você pode listar: É possível git grep para abas?

Testado no Ubuntu 18.04.


Answer #16

Coletando os melhores comentários da resposta de Gene , a melhor solução é, de longe, usar sponge de joeyh.name/code/moreutils .

sudo apt-get install moreutils
# The complete one-liner:
find ./ -iname '*.java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;

Explicação:

  • ./ está pesquisando recursivamente a partir do diretório atual
  • -iname é uma correspondência insensível a maiúsculas e minúsculas (para os gostos *.java e *.JAVA )
  • type -f encontra apenas arquivos regulares (sem diretórios, binários ou links simbólicos)
  • -exec bash -c executa os seguintes comandos em um subshell para cada nome de arquivo, {}
  • expand -t 4 expande todos os TABs para 4 espaços
  • sponge absorva a entrada padrão (da expand ) e grava em um arquivo (o mesmo) *.

OBSERVAÇÃO : * Um redirecionamento de arquivo simples ( > "$0" ) não funcionará aqui porque substituiria o arquivo muito em breve .

Vantagem : Todas as permissões de arquivo originais são mantidas e não são usados ​​arquivos tmp intermediários.





in-place