Quero pesquisar e substituir algum texto em um grande conjunto de arquivos, excluindo algumas instâncias. Para cada linha, quero um prompt perguntando se preciso substituí-la ou não. Algo semelhante ao vim :%s/from/to/gc
(com o c
prompt de confirmação), mas em um conjunto de pastas. Existe alguma ferramenta ou script de linha de comando que possa ser usado?
11
s/from/to/g
com uma falha de formatação depois dele, em vez des/from/to/gc
enfatizar oc
que você tentou escrever (você não pode fazer isso com o Markdown, você pode fazê-lo com<code>
e<strong>
tags HTML).Respostas:
Por que não usar o vim?
Abra todos os arquivos no vim
Ou abra apenas arquivos relevantes (como sugerido por Caleb)
E execute a substituição em todos os buffers
Você também pode fazê-lo
sed
, mas meu conhecimento é limitado.fonte
grep
vez de,find
para abrir apenas arquivos que tenham correspondências conhecidas.vim $(grep 'from' . -Rl)
Você pode fazer algo bruto com um pequeno script Perl que é instruído a executar substituições linha por linha (
-l -pe
) nos arquivos passados como argumentos (-i
):As possíveis melhorias seriam colorir partes do prompt e dar suporte a coisas como "substituir todas as ocorrências no arquivo atual". Solicitar separadamente cada ocorrência em uma linha seria mais difícil.
Segunda parte, combinando os arquivos. se não houver muitos arquivos envolvidos e você estiver executando o zsh, poderá corresponder todos os arquivos no diretório atual e seus subdiretórios recursivamente:
Se o seu shell for bash ≥4, você poderá executar
perl … **/*
, mas isso produzirá mensagens de erro falsas porque o sed tentará (e falhará) executar nos diretórios. Se você quiser executar a substituição apenas em um conjunto de arquivos, como arquivos C, poderá restringir as correspondências (que funcionam no bash ≥4 ou zsh):Se você precisar de um controle mais preciso sobre os arquivos que você está substituindo, ou se seu shell não possui a construção de correspondência de diretório recursiva
**
, ou se você tiver muitos arquivos e receber um erro de "linha de comando muito longa", usefind
. Por exemplo, para executar uma substituição em todos os arquivos nomeados*.h
ou*.c
no diretório atual e em seus subdiretórios (em sistemas mais antigos, pode ser necessário usá-lo em\;
vez de+
no final da linha (o+
formulário é mais rápido, mas não está disponível em todos os lugares).Dito isto, eu me ateria a um editor interativo se você precisar de interação. Gert mostrou uma maneira de fazer isso no Vim , embora exija a abertura de todos os arquivos pelos quais você deseja pesquisar, o que pode ser um problema se houver muito.
No Emacs, veja como você pode fazer isso:
M-x find-name-dired
(especifique um diretório de nível superior) ouM-x find-dired
(especifique umafind
linha de comando arbitrária ).t
para marcar todos os arquivos e, em seguida,Q
(dired-do-query-replace-regexp
) para executar uma substituição solicitando os arquivos marcados.fonte
sdiff
(consulte http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiff ) pode ser útil aqui. Com ele, você pode fazer patches interativos. Portanto, fazê-lo com um arquivo temporário que você criou executando operações de substituição usandosed
pode ser uma solução possível:(Loop de arquivo usando substituição de processo não POSIX e
read -d
conforme suportado, por exemplobash
.)fonte