A forma mais rápida de localizar e substituir uma string em vários arquivos HTML

3

Eu tenho vários arquivos HTML todos aninhados em pastas diferentes contidas em uma única pasta geral. Em cada um desses arquivos HTML eu preciso substituir

/contact/index.html

com

/contact/index.php

Existe uma maneira fácil de fazer isso a partir da linha de comando?

    
por Ben 01.09.2013 / 19:59

2 respostas

5

Sim, se você tiver o GNU find e o GNU sed , tente isso na pasta pai:

find . -type f \( -iname "*.htm" -o -iname "*.html" \) -exec sed -i.bak 's#/contact/index\.html#/contact/index.php#' '{}' +

Isso localizará todos os arquivos cujo nome termina em .html ou .HTML ou .htm ou .HTM (ou .HtM ...) e executará este comando sed neles:

sed -i.bak 's#/contact/index\.html#/contact/index.php#g'

Isso fará a substituição desejada e criará um backup do original foo.htm chamado foo.htm.bak . Se você não quiser os backups, basta remover .bak .

DETALHES:

O comando find , obviamente, localiza arquivos ou pastas. Sua sintaxe pode ser bastante complexa e é explicada em detalhes em seu man page , alguns dos quais são reproduzidos abaixo:

O formato geral é find [where] [what] . No exemplo que dei acima, o where é . , o que significa o diretório atual. O what é todos os arquivos que têm html ou extensão semelhante, então eu uso iname , que é:

   -iname pattern
          Like -name, but the match is case insensitive.
          For example,  the  patterns  'fo*'  and  'F??'
          match  the  file  names  'Foo',  'FOO', 'foo',
          'fOo', etc.   

No entanto, quero que corresponda aos dois html e htm , por isso, uso o -o flag, o que significa:

  expr1 -o expr2
          Or; expr2 is not evaluated if expr1 is true.

Tais construções precisam ser agrupadas, o que é feito pelos parênteses ( ) , que, no entanto, precisam ser que escapou do shell, então usamos \( e \) .

A mágica acontece na parte -exec :

   -exec command ;
          Execute command; true if 0 status is returned.
          All following arguments to find are  taken  to
          be  arguments to the command until an argument
          consisting of ';' is encountered.  The  string
          '{}'  is  replaced  by  the  current file name
          being processed everywhere it  occurs  in  the
          arguments  to  the  command, not just in argu‐
          ments where it is alone, as in  some  versions
          of  find.   [...] The specified command is
          run once for each matched file.   The  command
          is executed in the starting directory.   There
          are unavoidable security problems  surrounding
          use  of  the  -exec action; you should use the
          -execdir option instead.

Em outras palavras, dado um comando como -exec ls {} , find encontrará todos os arquivos correspondentes às condições que você definiu e iterará através deles, substituindo {} pelo nome do arquivo atual e executando o comando fornecido. Também estou usando + em vez de \; para finalizar a chamada exec porque isso fará com que find tente executar o menor número de comandos possível, isso é apenas uma pequena otimização, a menos que você tenha milhares de arquivos quando poderia ser importante:

   -exec command {} +
          This variant of  the  -exec  action  runs  the
          specified  command  on the selected files, but
          the command line is built  by  appending  each
          selected  file name at the end; the total num‐
          ber of invocations of the command will be much
          less  than  the  number of matched files.  The
          command line is built in  much  the  same  way
          that xargs builds its command lines.  Only one
          instance of '{}' is allowed  within  the  com‐
          mand.  The command is executed in the starting
          directory.

Finalmente, sed é um editor de fluxo de texto de linha de comando, ele aplicará o comando que você atribuiu a cada linha de um arquivo. Neste caso, o comando é uma substituição, o formato básico é:

s#pattern#replacement#flags

Os delimitadores ( # ) podem ser qualquer caractere especial e são tradicionalmente / , mas eu escolhi # porque senão eu teria que escapar do / . Observe que ChrisDown em sua resposta escolheu usar | . Isto é simplesmente uma escolha pessoal e os dois são equivalentes.

    
por 01.09.2013 / 20:10
3

Supondo que você tenha o GNU sed :

find -iname '*.html' -type f -exec sed -i 's|/contact/index\.html|/contact/index.php|g' {} +
    
por 01.09.2013 / 20:11