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.