Você pode fazer algo cru com um pequeno script Perl que é instruído a realizar substituições linha a linha ( -l -pe
) nos arquivos transmitidos como argumentos ( -i
):
perl -i -l -pe '
if (/from/) { # is the source text present on this line?
printf STDERR ("%s: %s [y/N]? ", $ARGV, $_); # display a prompt
$r=<STDIN>; # read user response
if ($r =~ /^[Yy]/) { # if user entered Y:
s/from/to/g; # replace all occurences on this line
}' /path/to/files
Possíveis melhorias seriam colorir partes do prompt e suportar 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, será possível corresponder todos os arquivos no diretório atual e em seus subdiretórios de forma recursiva:
perl -i -l -pe '…' **/*(.)
Se o seu shell é bash ≥4, você pode executar perl … **/*
, mas isso produzirá mensagens de erro espúrias porque o sed tentará (e falhará) rodar em diretórios. Se você quiser apenas realizar a substituição em um conjunto de arquivos, como arquivos C, poderá restringir as correspondências (que funcionam em bash ≥4 ou zsh):
perl -i -l -pe '…' **/*.[hc]
Se você precisar de um controle mais preciso sobre quais arquivos está substituindo, ou se o seu shell não tiver 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", use find
. Por exemplo, para executar uma substituição em todos os arquivos denominados *.h
ou *.c
no diretório atual e em seus subdiretórios (em sistemas mais antigos, talvez seja necessário usar \;
em vez de +
no final da linha ( o formulário +
é mais rápido, mas não está disponível em todos os lugares).
find . -type f -name '*.[hc]' -exec perl -i -l -pe '…' {} +
Dito isso, eu ficaria com um editor interativo se você precisar de interação. Gert mostrou um 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:
- Reúna os nomes dos arquivos com
M-x find-name-dired
(especifique um diretório de nível superior) ou M-x find-dired
(especifique uma linha de comando find
arbitrária).
- No buffer resultante dired , pressione
t
para marcar todos arquivos, então Q
( dired-do-query-replace-regexp
) para execute uma substituição com aviso nos arquivos marcados.