Eu preciso substituir o caminho para a imagem em vários arquivos xhtml no diretório. A parte principal dos arquivos é a seguinte:
<?xml version="1.0" encoding="UTF-8"?>
<html xml:lang="en-us" lang="en-us" xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xmlns:ns="http://www.w3.org/2001/10/synthesis">
<head>
Tentei fazer isso com sed
comando, mas não funciona. Possivelmente devido a uma versão específica do sed, mas não tenho certeza. Eu tenhoGNU sed 4.4
original path:
<img src="/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"
I need replace to:
<img src="graphics/line.jpg"
eu tentei
sed -i '.bak' 's/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g' '*.xhtml'
ele retorna
sed: -e expression #1, char 1: unknown command: `.'
também tentei
sed -i ' ' 's/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g' '*.xhtml'
it return
sed: can't read s/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g: No such file or directory
sed: can't read *.xhtml: No such file or directory
O sed
indicado é para isso?
O
sed
utilitário geralmente não é adequado para editar arquivos XML ou XHTML. XML é um formato de documento estruturado e não orientado a linhas. Como muitas ferramentas padrão de manipulação de texto Unix, osed
utilitário é orientado a linhas e não lida com coisas como a codificação ou decodificação de entidades XML sem esforço extra.Seu documento de exemplo contém o nó (corrigido para incluir
/>
no final)Como o espaço em branco (espaços, tabulações e novas linhas) dentro dos nós é arbitrário, e não sabemos sobre outros atributos do
img
nó ou sua ordenação, isso seria complicado de analisar comsed
. Também devemos garantir que o nome do caminho não seja substituído em nenhum outro lugar que não seja osrc
atributo de umimg
nó.Usar um analisador XML de linha de comando para fazer isso pode ficar assim:
Estamos usando
xmlstarlet
, um analisador XML razoavelmente conhecido para a linha de comando, para substituir o valor de cadasrc
atributo de cadaimg
nó pela stringgraphics/line.jpg
se o valor original do atributo fosse/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg
.O comando grava o resultado da operação na saída padrão, mas você pode fazer
xmlstarlet
a edição no local usando sua opção--inplace
(ou-L
) após o teste para ter certeza de que parece estar funcionando como você espera que funcione.Se suas
img
tags se parecem com<img src="...">
, sem um final adequado, você pode se recuperar disso filtrando primeiro seus arquivos XHTMLPode-se até imaginar um pipeline no formulário
Se todos os arquivos que você deseja processar corresponderem ao padrão
./*.xhtml
, ou seja, se eles tiverem um.xhtml
sufixo de nome de arquivo e estiverem no diretório atual, você poderá processar todos esses arquivos com qualquer um dos comandos acima usando um simples loop de shell.Observe que isso usa a
--inplace
opção dexmlstarlet
, que modificaria os arquivos sem fazer backups. Seria melhor se você executasse isso em dados de backup.Para executar o acima em todos os arquivos XHTML em uma hierarquia de diretórios, ou seja, em um diretório com vários subdiretórios, você pode usar
find
.Se for XHTML, você pode editá-lo com um editor de XML adequado. A vantagem aqui é que é impermeável a alterações de layout do arquivo
Primeiro, conserte seu exemplo para ser XML (afinal, é um documento XHTML),
Se o seu documento de origem não for realmente XHTML, você pode corrigi-lo programaticamente com
Você pode editar o
src
atributo comxmlstarlet
:Ou combinando os dois comandos,
Quando estiver pronto, coloque o resultado em um arquivo temporário e substitua o original pela versão modificada. (Ou renomeie o original como backup e use-o como entrada para criar um arquivo com o nome original.)
Se você tiver vários
<img/>
elementos, poderá fornecer um caminho de estrutura para eles em vez de apenas//img
. Se você deseja alterar apenas aqueles que possuem umsrc
valor de atributo específico, isso também é possível. Mas não há detalhes suficientes em sua pergunta para abordar essas possibilidades de maneira útil.Tentar :
Outra opção se você não quiser escapar das barras é usar
rpl
.Em uma distribuição baseada em Debian:
manual para rpl
A
-i
opção exige que seu valor siga imediatamente, sem nenhum espaço entre eles. Então você teria que escrever-i.bak
. Com o espaço,sed
interpreta isso como-i
sem um valor (para que o arquivo seja alterado no local) e.bak
como o comando a ser executado, daí a mensagem de erro. Você também precisaria remover as aspas*.html
para permitir que o shell expandisse o curinga.(Sua segunda tentativa basicamente tem o mesmo problema, mas aqui o espaço como um comando não aciona uma mensagem de erro.)
A propósito, você pode tornar seu
sed
comando mais legível usando um separador diferente/
para não precisar escapar das barras em sua string para substituir, por exemplo:Você também pode tentar isso
sed
. Não incluí o-i
sinalizador, pois é inadequado durante o teste.Isso agrupará as correspondências que precisamos reter, excluindo as que não precisamos.
(.*=.)
- Agrupa tudo até a última ocorrência de=
.[^"]*
- É uma partida excluída.[^"]
é usado para evitar que a correspondência vá para o último/
e corresponda até o próximo"
(/.*)
- Tudo até o penúltimo/
foi excluído enquanto corresponde ao padrão restante depois.\1graphics\2
- Duas partidas de grupo foram criadas, podemos devolvê-las na ordem que quisermos. Comographics
precisa ser codificado após=
, podemos inseri-lo imediatamente após retornar a primeira correspondência agrupada\1
|
- Pipes foram usados como delimitadores, pois os próprios dados contêm barras '/' que entrarão em conflito comseds
os delimitadores padrão.Resultado
Certamente existem fortes argumentos contra o uso
sed
para tal coisa, e outros os fizeram.No entanto, você pode não estar em condições de usar as ferramentas especializadas mencionadas. Então, se seus arquivos de entrada são adequadamente previsíveis em sua estrutura para permitir
sed
o trabalho, esta é a maneira que eu faria:Está se esforçando (razoavelmente) para garantir que esteja operando nas linhas corretas, mencionando um pouco de contexto na expressão de pesquisa.
Uma observação sobre
sed
o uso: o primeiro caractere após os
comando dita o delimitador, o que nos permite trabalhar/
sem a necessidade de escape.