sed várias instruções dentro de um único comando não está funcionando

2

Estou em um enigma. Coloque o mais simples possível, estou tentando criar parte de um script que irá editar o arquivo / etc / sudoers no linux utilizando sed. Devido à conta que estou usando, eu preciso fazer isso editando WITH sudo executando o comando sed. Devido a isso, no entanto, não posso terminar o comando antes de fazer todas as edições no arquivo, caso contrário, vou me bloquear.

Eu estou especificamente tentando modificar o grupo de roda% dentro do arquivo / etc / sudoers, e existem entradas preexistentes dentro do arquivo em vários servidores. Quero adicionar minha própria entrada otimizada, comentar as entradas mais antigas e, finalmente, garantir que a entrada I JUST adicionada não seja comentada.

Eu criei instruções em sed para fazer isso, e elas são executadas individualmente muito bem, é quando tento fazer qualquer coisa para permitir várias instruções no mesmo comando que nenhuma função de instrução. (Mesmo que eu não tenha erros de sintaxe)

Por exemplo, minhas declarações:

sudo sed 's/.*wheel/#&/' /etc/sudoers

---- funciona bem por si só

sudo sed 's/^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)//' /etc/sudoers   

---- também funciona muito bem por si só

No entanto, como preciso combiná-los em um único comando, as coisas param de funcionar ..... como:

sudo sed 's/(.*wheel/#&) (^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\))/' /etc/sudoers   -

--- Não, não há dados

Ou

sudo sed -e 's/.*wheel/#&/' -e 's/^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)//' /etc/sudoers   

---- Não funciona também

Etc, etc, nada nesse sentido parece resolver o problema. A saída depois que eu executo os 2 comandos acima mostra que ela está inalterada como se eu tivesse acabado de rodar um gato no arquivo original. (sim, eu sei que não estou editando permanentemente o arquivo no lugar no segundo)

Agora eu entendo que sim ... Eu poderia adicionar uma entrada temporária na parte inferior do arquivo para o meu usuário começar e, em seguida, excluí-la como a última etapa para contornar isso. Ou eu poderia executar um script com um loop e provavelmente também ser bem-sucedido, mas tem que haver uma maneira mais elegante de fazer isso com um único comando como eu pretendia.

Alguém tem alguma ideia? Além disso, se há uma maneira melhor de fazer o que pretendo fazer em primeiro lugar, eu estaria interessado em saber.

EDIT: exemplos de entrada / saída:

As linhas que estão no arquivo por padrão:

%wheel  ALL=(ALL)       ALL
%wheel  ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL   ---added by me in a previous step
#%wheel  ALL=(ALL)       NOPASSWD: ALL

Eu quero que o produto final depois do sed seja executado assim:

#%wheel  ALL=(ALL)       ALL
%wheel  ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL   
#%wheel  ALL=(ALL)       NOPASSWD: ALL

Eu não quero que seja assim:

#%wheel  ALL=(ALL)       ALL
#%wheel  ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL   
#%wheel  ALL=(ALL)       NOPASSWD: ALL

E eu não quero que seja assim:

%wheel  ALL=(ALL)       ALL
%wheel  ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL   
%wheel  ALL=(ALL)       NOPASSWD: ALL

Assim como é agora, o comando multiple statement sed não parece fazer nada, é somente quando eu os executo como comandos separados que eu recebo a saída desejada. (o que não posso fazer nesta circunstância)

Qualquer ajuda seria apreciada!

    
por Viscosity 15.08.2016 / 20:07

2 respostas

2

Edição final após o exemplo adicionado à pergunta original:

Seu segundo comando sed com duas expressões '-e' funciona corretamente para mim na entrada de exemplo fornecida, usando o Debian Jessie / sed (GNU sed) 4.2.2. (Bem, na maioria das vezes. A última linha termina com 2 caracteres de comentário, mas isso não deve ser um grande problema.) Não tenho certeza se há alguma variação na maneira como diferentes versões de sed tratam de múltiplas expressões?

Não é a minha solução preferida, mas se você está tendo problemas para obter o sed para se comportar de maneira previsível com várias expressões, você também pode usar tee no final de um pipeline de comandos sed individuais.

sudo cat /etc/sudoers | { multiple sed commands in pipeline } | sudo tee /etc/sudoers

Primeiro edite depois de alguns esclarecimentos nos comentários:

Se a linha que você está adicionando for comentada antes da execução sed, então o primeiro regex está adicionando um segundo caractere de comentário a ela. Com dois caracteres '#' no início da linha, a segunda instrução não combina mais e não faz nada. Uma edição fácil é usar o modificador 1 ou mais no caractere '#' na segunda expressão:

sudo sed -e 's/.*wheel/#&/' -e 's/^#\+\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)//' /etc/sudoers   

Resposta original:

Se eu não estou confundindo seus regexes, seu segundo comando é desfazer o primeiro. Como um exemplo simplificado:

echo a | sed -e 's/a/b/' -e 's/b/a/'

imprime a . Várias expressões são executadas em seqüência para cada linha.

Uma opção seria usar um delimitador de comentário alternativo na primeira etapa e, em seguida, adicionar uma terceira etapa para substituí-la. Por exemplo, em vez de adicionar um '#' ao início da linha na primeira expressão, use 's/.*wheel/--&/' . Em seguida, após a segunda expressão ter descomentado as linhas desejadas, adicione um terceiro -e 's/^--/#/' para limpá-lo.

    
por 15.08.2016 / 20:21
1

Como eu entendo o OP, é necessário marcar todas as linhas com roda como comentário, exceto com o texto %wheel\s\+ALL …

sudo sed '
    /%wheel\s\+ALL=(ALL)\s*NOPASSWD:\s*LOG_INPUT:\s*LOG_OUTPUT:\s*ALL/{
        s/^#\+\s*//
        b
    }
    /^[^#].*wheel/s/^/#/
    ' /etc/sudoers
    
por 15.08.2016 / 21:36

Tags