AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 670634
Accepted
minto
minto
Asked: 2021-09-26 13:33:25 +0800 CST2021-09-26 13:33:25 +0800 CST 2021-09-26 13:33:25 +0800 CST

sed para substituir o caminho para a imagem

  • 772

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 sedcomando, 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 sedindicado é para isso?

bash shell-script
  • 6 6 respostas
  • 816 Views

6 respostas

  • Voted
  1. they
    2021-09-26T14:41:53+08:002021-09-26T14:41:53+08:00

    O sedutilitá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, o sedutilitá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)

    <img src="/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg" />
    

    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 imgnó ou sua ordenação, isso seria complicado de analisar com sed. Também devemos garantir que o nome do caminho não seja substituído em nenhum outro lugar que não seja o srcatributo de um imgnó.

    Usar um analisador XML de linha de comando para fazer isso pode ficar assim:

    xmlstarlet ed   \
            -u '//img/@src[. = "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"]' \
            -v 'graphics/line.jpg' file.xhtml
    

    Estamos usando xmlstarlet, um analisador XML razoavelmente conhecido para a linha de comando, para substituir o valor de cada srcatributo de cada imgnó pela string graphics/line.jpgse 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 xmlstarleta 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 imgtags se parecem com <img src="...">, sem um final adequado, você pode se recuperar disso filtrando primeiro seus arquivos XHTML

    xmlstarlet fo --recover --html file.xhtml
    

    Pode-se até imaginar um pipeline no formulário

    xmlstarlet fo --recover --html file.xhtml |
    xmlstarlet ed   \
            -u '//img/@src[. = "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"]' \
            -v 'graphics/line.jpg'
    

    Se todos os arquivos que você deseja processar corresponderem ao padrão ./*.xhtml, ou seja, se eles tiverem um .xhtmlsufixo 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.

    for name in ./*.xhtml; do
            xmlstarlet ed --inplace        \
                    -u '//img/@src[. = "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"]'   \
                    -v 'graphics/line.jpg' "$name"
    done
    

    Observe que isso usa a --inplaceopção de xmlstarlet, 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.

    find . -type f -name '*.xhtml' -exec sh -c '
            for name do
                    xmlstarlet ed --inplace        \
                            -u "//img/@src[. = \"/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg\"]" \
                            -v "graphics/line.jpg" "$name"
            done' sh {} +
    
    • 5
  2. roaima
    2021-09-26T14:44:12+08:002021-09-26T14:44:12+08:00

    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),

    <img src="/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"/>
    

    Se o seu documento de origem não for realmente XHTML, você pode corrigi-lo programaticamente com

    xmlstarlet format -H file.xhtml
    

    Você pode editar o srcatributo com xmlstarlet:

    xmlstarlet edit --omit-decl --update '//img/@src' --value 'graphics/line.jpg' file.xhtml
    <img src="hello"/>
    

    Ou combinando os dois comandos,

    xmlstarlet fo -H file.xhtml 2>/dev/null |
        xmlstarlet ed -u '//img/@src' -v 'graphics/line.jpg'
    

    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 um srcvalor 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.

    • 4
  3. Best Answer
    Gounou
    2021-09-26T14:04:59+08:002021-09-26T14:04:59+08:00

    Tentar :

    sed -i.bak 's/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g' *.xhtml
    
    
    sed -i '.bak' --> sed -i.bak
    '*.xhtml' --> *.xhtml
    

    Outra opção se você não quiser escapar das barras é usar rpl.

    Em uma distribuição baseada em Debian:

    sudo apt install rpl
    
    rpl -b "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg" "graphics/line.jpg" *.xhtml
    
    -b = backup
    

    manual para rpl

    • 1
  4. DonHolgo
    2021-09-26T14:08:21+08:002021-09-26T14:08:21+08:00

    A -iopçã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, sedinterpreta isso como -isem um valor (para que o arquivo seja alterado no local) e .bakcomo o comando a ser executado, daí a mensagem de erro. Você também precisaria remover as aspas *.htmlpara 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 sedcomando mais legível usando um separador diferente /para não precisar escapar das barras em sua string para substituir, por exemplo:

    sed -i.bak 's-/api/v2/epubs/urn:orm:book:381260143574/files-graphics-g' *.xhtml
    
    • 1
  5. HatLess
    2021-09-27T01:00:19+08:002021-09-27T01:00:19+08:00

    Você também pode tentar isso sed. Não incluí o -isinalizador, pois é inadequado durante o teste.

    sed -E 's|(img src=").[^"]*(/.*)|\1graphics\2|' input_file
    

    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. Como graphicsprecisa 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 com sedsos delimitadores padrão.

    Resultado

    $ sed -E 's|(img src=").[^"]*(/.*)|\1graphics\2|' input_file
    <img src="graphics/line.jpg"/>
    
    • 1
  6. bxm
    2021-09-27T00:58:43+08:002021-09-27T00:58:43+08:00

    Certamente existem fortes argumentos contra o uso sedpara 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 sedo trabalho, esta é a maneira que eu faria:

    sed -ri.bak 's (src=").*/files/(.+[.]jpg") \1graphics/\2 g' *.xhtml
    

    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 sedo uso: o primeiro caractere após o scomando dita o delimitador, o que nos permite trabalhar /sem a necessidade de escape.

    • 0

relate perguntas

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • MySQL Select com função IN () com array bash

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve