Como executar um comando somente se sed substituir strings

6

Eu quero habilitar o repositório multiverse no Ubuntu por uma linha de comando.

sed -i "/^# deb.*multiverse/ s/^# //" /etc/apt/sources.list && apt-get update

Esse comando executará apt-get update todas as vezes, mas será necessário somente quando sed comentar a linha.

Existe uma maneira fácil de detectar se sed substitui strings e executa um comando dependendo desse resultado?

    
por ironsand 23.12.2014 / 21:20

5 respostas

4

Provavelmente, a melhor coisa a fazer aqui é apenas grep para a linha comentada primeiro:

grep -q '^# deb.*multiverse' /etc/apt/sources.list &&
  sed -i '/^# deb.*multiverse/ s/^# //' /etc/apt/sources.list &&
  apt-get update
    
por 23.12.2014 / 22:12
6

Eu sei que esta pergunta já tem uma resposta, mas fiquei curioso para ver se poderia chegar a uma resposta somente para o sed (sem usar o grep como na resposta aceita). Como se vê, parece possível:

sed -ni '/^# deb.*multiverse/{;h;s/^# //;};p;${;g;/^#/!q1;}' /etc/apt/sources.list
  && apt-get update

(Claro, tudo deve estar na mesma linha, mas eu queria que tudo ficasse visível sem ter que rolar horizontalmente).

Explicação:

  • Procure o padrão ( /^# deb.*multiverse/ )
  • Se encontrado:
    • Mantenha a linha no buffer de retenção ( h )
    • Faça o descomentamento ( s/^# // )
  • Imprimir a linha
  • Apenas na última linha ( $ )
    • Copie a linha mantida no buffer de retenção para o buffer de padrões ( g )
    • Teste se o buffer de espera começa com um sinal de comentário (estaria vazio se não houvesse substituição) ( /^#/ )
    • Se não tivermos uma correspondência, saia com o código 1 para sinalizar que nenhuma substituição foi feita ( !q1 ) (senão sai normalmente com o código 0 )

Agora eu sei que esta resposta não é tão clara quanto simplesmente usar o grep, mas eu estava interessado no desafio e descobri isso, então eu pensei em compartilhar.

    
por 24.12.2014 / 00:50
3
{   sed -i '/^# \(deb.*multiv.*\)/h;s///p
        $x;s//apt-get update/w /dev/fd/2' file
}   2>&1 >/dev/null | sh -v

Esse comando emitirá apenas a linha apt-get update alimentada para sh sobre um pipe se ele fizer pelo menos uma substituição ao ler file .

    
por 23.12.2014 / 22:33
1

sed não tem variáveis. Há o comando t que salta para um rótulo após um s/// bem-sucedido e o comando q recebe um código de saída. Mas como você está reescrevendo o arquivo, não é possível sair após a substituição, você precisa ler o arquivo inteiro primeiro.

Eu mudaria para outro idioma. perl trabalha aqui: novas linhas para legibilidade

perl -i -pe '
    BEGIN {$x=1} 
    if (/^# deb.*multiverse/) {s/^# //; $x=0}
    END {exit $x}
' /etc/apt/sources.list &&
apt-get update
    
por 23.12.2014 / 21:59
1

Outra maneira de fazer isso é com ed , aproveitando-se de um recurso interno: se nenhuma substituição for feita nas linhas endereçadas, isso é considerado um erro; se a entrada padrão for um arquivo regular, ed deverá terminar com um status de saída diferente de zero . Você poderia usar herestring :

ed -s /etc/apt/sources.list <<< $',s/^# \(deb.*multiverse\)/\1/\nw\n!apt-get update\nq'

ou heredoc :

ed -s /etc/apt/sources.list <<IN
,s/^# \(deb.*multiverse\)//
w
!apt-get update
q
IN

para passar os seguintes comandos para ed :

,s/^# \(deb.*multiverse\)//      replace pattern with something 
w                                  write changes to file
!apt-get update                    run this command in shell
q                                  quit editor

No entanto, se nenhuma correspondência for encontrada, significa que não há s ubstitution, então ed explode (a única saída é um ponto de interrogação ? significando error 1 ) e como resultado, os subcomandos nas linhas subsequentes não são executados. Para testá-lo, você pode substituir apt-get update por outro comando como cat /etc/apt/sources.list ou echo DONE .

1: Se o ponto de interrogação lhe incomoda, basta redirecionar stderr para /dev/null , por exemplo:

ed -s /etc/apt/sources.list 2>/dev/null <<....
    
por 19.02.2015 / 14:33

Tags