Substituir seqüências de caracteres em arquivos com base em determinados critérios de pesquisa é uma tarefa muito comum. Como posso
- substituir string
foo
porbar
todos os arquivos no diretório atual? - fazer o mesmo recursivamente para subdiretórios?
- substituir apenas se o nome do arquivo corresponder a outra sequência?
- substituir apenas se a string for encontrada em um determinado contexto?
- substituir se a string estiver em um determinado número de linha?
- substituir várias strings pela mesma substituição
- substituir várias strings por diferentes substituições
text-processing
awk
sed
perl
terdon
fonte
fonte
Respostas:
1. Substituindo todas as ocorrências de uma sequência por outra em todos os arquivos no diretório atual:
Esses são casos nos quais você sabe que o diretório contém apenas arquivos regulares e que deseja processar todos os arquivos não ocultos. Se não for esse o caso, use as abordagens em 2.
Todas as
sed
soluções nesta resposta assumem o GNUsed
. Se estiver usando o FreeBSD ou OS / X, substitua-i
por-i ''
. Observe também que o uso do-i
comutador com qualquer versão dosed
tem certas implicações na segurança do sistema de arquivos e é desaconselhável em qualquer script que você planeja distribuir de qualquer forma.Arquivos não recursivos, apenas neste diretório:
(o
perl
que falhará para nomes de arquivos terminados em|
ou espaço) ).Arquivos regulares e recursivos ( incluindo os ocultos ) neste e em todos os subdiretórios
Se você estiver usando o zsh:
(pode falhar se a lista for muito grande, consulte
zargs
a solução alternativa).O Bash não pode verificar diretamente se há arquivos regulares, é necessário um loop (chaves evitam definir as opções globalmente):
Os arquivos são selecionados quando são arquivos reais (-f) e são graváveis (-w).
2. Substitua apenas se o nome do arquivo corresponder a outra sequência / tiver uma extensão específica / for de um determinado tipo, etc:
Arquivos não recursivos, apenas neste diretório:
Arquivos regulares e recursivos neste e em todos os subdiretórios
Se você estiver usando o bash (chaves, evite definir as opções globalmente):
Se você estiver usando o zsh:
O
--
serve para dizersed
que não haverá mais sinalizadores na linha de comando. Isso é útil para proteger contra nomes de arquivos começando com-
.Se um arquivo é de um determinado tipo, por exemplo, executável (veja
man find
para mais opções):zsh
:3. Substitua apenas se a sequência for encontrada em um determinado contexto
Substitua
foo
porbar
apenas se houverbaz
mais tarde na mesma linha:Em
sed
, o uso\( \)
salva salva o que estiver entre parênteses e você pode acessá-lo com\1
. Existem muitas variações deste tema, para aprender mais sobre essas expressões regulares, veja aqui .Substitua
foo
porbar
apenas sefoo
for encontrado na coluna 3d (campo) do arquivo de entrada (assumindo campos separados por espaços em branco):(precisa
gawk
4.1.0 ou mais recente).Para um campo diferente, use
$N
ondeN
está o número do campo de interesse. Para um separador de campo diferente (:
neste exemplo), use:Outra solução usando
perl
:NOTA: as soluções
awk
eperl
afetarão o espaçamento no arquivo (remova os espaços em branco à esquerda e à direita e converta seqüências de espaços em branco em um caractere de espaço nas linhas correspondentes). Para um campo diferente, use$F[N-1]
ondeN
é o número do campo desejado e para um separador de campos diferente (ele$"=":"
define o separador de campos de saída:
):Substitua
foo
porbar
apenas na quarta linha:4. Operações de substituição múltipla: substitua por cordas diferentes
Você pode combinar
sed
comandos:Esteja ciente de que a ordem é importante (
sed 's/foo/bar/g; s/bar/baz/g'
será substituídafoo
porbaz
).ou comandos Perl
Se você tiver um grande número de padrões, é mais fácil salvar seus padrões e suas substituições em um
sed
arquivo de script:Ou, se você tiver muitos pares de padrões para que o acima seja possível, você poderá ler pares de padrões de um arquivo (dois padrões separados por espaço, $ pattern e $ Replacement, por linha):
Isso será bastante lento para longas listas de padrões e grandes arquivos de dados, portanto, você pode querer ler os padrões e criar um
sed
script a partir deles. O seguinte pressupõe que um delimitador <space> separa uma lista de pares REPLACE MATCH <space> ocorrendo um por linha no arquivopatterns.txt
:O formato acima é amplamente arbitrário e, por exemplo, não permite um <espaço> em MATCH ou REPLACE . O método é muito geral: basicamente, se você pode criar um fluxo de saída que se parece com um
sed
script, pode originar esse fluxo como umsed
script, especificandosed
o arquivo de script como-
stdin.Você pode combinar e concatenar vários scripts da mesma maneira:
Um POSIX
sed
concatenará todos os scripts em um na ordem em que aparecem na linha de comando. Nenhuma delas precisa terminar em uma linha\n
eletrônica.grep
pode funcionar da mesma maneira:Ao trabalhar com seqüências fixas como padrões, é uma boa prática escapar dos metacaracteres de expressão regular . Você pode fazer isso facilmente:
5. Operações de substituição múltipla: substitua vários padrões pela mesma sequência
Substituir qualquer um
foo
,bar
oubaz
comfoobar
ou
fonte
zsh
. Adicione todas aszsh
informações, mas não há motivo para remover o material do bash. Além disso, eu sei que o uso do shell para processamento de texto não é ideal, mas há casos em que é necessário. Editei uma versão melhor do meu script original que criará umsed
script em vez de realmente usar o loop de shell para analisar. Isso pode ser útil se você tiver várias centenas de pares de padrões, por exemplo.(.)
qualificador de globbing, portanto não pode ser usado aqui. (você está perdendo alguns - também). O loop for está incorreto (ausente -r) e significa fazer várias passagens nos arquivos e não traz nenhum benefício sobre um script sed.--
depoissed -i
e antes do comando substituto?-
. Utilizá-lo garante que os comandos funcionem em arquivos com nomes como-foo
. Sem ele, o-f
seria analisado como uma opção..git
diretório e atrapalharão seu checkout. Melhor operar dentro / em diretórios específicos por nome.Um bom r e pl acement ferramenta Linux é rpl , que foi originalmente escrito para o projeto Debian, por isso está disponível com
apt-get install rpl
em qualquer distro derivada do Debian, e pode ser para os outros, mas caso contrário, você pode baixar otar.gz
arquivo em SourgeForge .Exemplo mais simples de uso:
Observe que se a sequência contiver espaços, ela deverá ser colocada entre aspas. Por padrão,
rpl
cuide de letras maiúsculas, mas não de palavras completas , mas você pode alterar esses padrões com as opções-i
(ignorar maiúsculas e minúsculas) e-w
(palavras inteiras). Você também pode especificar vários arquivos :Ou até especifique as extensões (
-x
) a serem pesquisadas ou até mesmo recursivamente (-R
) no diretório:Você também pode procurar / substituir no modo interativo com a
-p
opção (prompt):A saída mostra os números de arquivos / sequência substituídos e o tipo de pesquisa (maiúsculas / minúsculas, palavras inteiras / parciais), mas pode ficar em silêncio com a opção
-q
( modo silencioso ), ou ainda mais detalhada, listando números de linhas que contêm corresponde a cada arquivo e diretório com a opção-v
( modo detalhado ).Outras opções que merecem ser lembradas são
-e
(honor e scapes) que permitemregular expressions
, assim você também pode pesquisar abas (\t
), novas linhas (\n
), etc. Mesmo você pode usar-f
para forçar permissões (é claro, somente quando o usuário tiver permissões de gravação) e-d
preservar os tempos de modificação`).Por fim, se você não tiver certeza sobre o que fará exatamente, use o
-s
( modo de simulação ).fonte
Como fazer uma pesquisa e substituir vários arquivos sugere:
Meus melhores resultados vêm do uso de perl e grep (para garantir que o arquivo tenha a expressão de pesquisa)
fonte
Você pode usar o Vim no modo Ex:
fonte
Eu usei isso:
Listar todos os arquivos que contêm
old_string
.Substitua nova linha no resultado por espaços (para que a lista de arquivos possa ser alimentada
sed
.Execute
sed
esses arquivos para substituir a string antiga por nova.Atualização: O resultado acima falhará nos nomes de arquivos que contêm espaços em branco. Em vez disso, use:
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
fonte
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
permitirá lidar com nomes de arquivos arbitrários.Da perspectiva do usuário, é uma ferramenta Unix agradável e simples que faz o trabalho perfeitamente
qsubst
. Por exemplo,será substituído
foo
porbar
todos os meus arquivos C. Um recurso interessante é queqsubst
vai fazer uma consulta de substituir , ou seja, ele vai me mostrar cada ocorrênciafoo
e perguntar se eu quero substituí-lo ou não. [Você pode substituir incondicionalmente (sem perguntar) pela-go
opção, e existem outras opções, por exemplo,-w
se você deseja substituir apenasfoo
quando se trata de uma palavra inteira.]Como obtê-lo:
qsubst
foi inventado por der Mouse (de McGill) e publicado no comp.unix.sources 11 (7) em agosto de 1987. Existem versões atualizadas. Por exemplo, a versão do NetBSDqsubst.c,v 1.8 2004/11/01
compila e roda perfeitamente no meu mac.fonte
Eu precisava de algo que iria fornecer uma opção dry-run e iria trabalhar de forma recursiva com um glob, e depois de tentar fazê-lo com
awk
esed
eu desisti e em vez fez isso em python.O script pesquisa recursivamente todos os arquivos que correspondem a um padrão glob (por exemplo
--glob="*.html"
) para uma regex e substitui pela regex de substituição:Toda opção longa, como
--search-regex
tem uma opção curta correspondente, ie-s
. Corra com-h
para ver todas as opções.Por exemplo, isso mudará todas as datas de
2017-12-31
para31-12-2017
:fonte
globstar
e**
globs oufind
. Para uma corrida a seco, basta usarsed
. A menos que você use a-i
opção, ela não fará nenhuma alteração. Para um uso de backupsed -i.bak
(ouperl -i .bak
); para arquivos que não correspondem, usegrep PATTERN file || echo file
. E por que você faria o python expandir a glob em vez de deixar o shell fazer isso? Por que aoscript.py --glob=foo*
invés de apenasscript.py foo*
?sed
e estáawk
bem e não está disposto a investir tempo extra para dominá-los, (4) legibilidade, (5) essa solução também funcionará em sistemas não-posix (não que eu precise disso, mas que outra pessoa possa).O ripgrep (nome do comando
rg
) é umagrep
ferramenta, mas também suporta pesquisa e substituição.rg
não suporta a opção no local, então você terá que fazer isso sozinhoConsulte a documentação do Rex regex para obter sintaxe e recursos para expressões regulares. O
-P
switch ativará o sabor PCRE2 .rg
suporta Unicode por padrão.Assim
grep
, a-F
opção permitirá que as seqüências fixas sejam correspondidas, uma opção útil que eu acho quesed
deveria implementar também.Outra opção útil é a
-U
que permite a correspondência multilinharg
também pode lidar com arquivos no estilo dosOutra vantagem
rg
é que é provável que seja mais rápido do quesed
fonte