Como alterar um conjunto de caracteres entre delimitadores para a linha exata?

4

Estou tentando escrever um script para alterar a senha do usuário no banco de dados do usuário dovecot e não consigo entender como substituir um conjunto de caracteres entre delimitadores para linhas exatas com sed .

Por favor, verifique esta linha, por exemplo (esta é a parte do dovecot userdb):

[email protected]:{SHA512-CRYPT}$6$0vthg.LubtSCxRRK$MdTKNQ2Vk8ZW3XQXNXStt9rfr6fNa‌​XqPvZ0o9WJ8mW8y9ozE1pi8dYM8oQzwWa8ESGzEmJO6yT/tgi3ZEqAiE0:::
[email protected]:{SHA512-CRYPT}$6$0vthg.LubtSCxRRK$MdTKNQ2Vk8ZW3XQXNXStt9rfr6fNa‌​XqPvZ0o9WJ8mW8y9ozE1pi8dYM8oQzwWa8ESGzEmJO6yT/tgi3ZEqAiE0:::

Como substituir a string entre os delimitadores ":" começando com "{SHA512-CRYPT}" apenas para o usuário "[email protected]" e não para o usuário "[email protected]" com sed?

    
por powerthrash 28.11.2014 / 19:43

3 respostas

8

Talvez:

sed 's/\(\(^\|:\)123@example\.com:\)\([^:]\+\)/foo/'

, pois não há delimitadores com escape no valor.

sed 's/\(\(^\|:\)123@example\.com:\)\([^:]\+\)/foo/'    
     |     |         |                |     | |  | |     
     |     |         |                |     | |  | +----- H. End of sub.
     |     |         |                |     | |  +------- G. Sub string
     |     |         |                |     | +---------- F. Match Group 1.
     |     |         |                |     +------------ E. End of Group 3.
     |     |         |                +------------------ D. Group 3.
     |     |         +----------------------------------- C. User
     |     +--------------------------------------------- B. Prefix Group 2.
     +--------------------------------------------------- A. Substitute
  • A: s/ Substitua o comando.
  • B: (^|:) Começa com o início da linha ou delimitador : , Grupo 2, parte do grupo de correspondência 1.
  • C: O usuário corresponde, parte do grupo de correspondências 1.
  • D: ([^:]+) A parte para remover, qualquer coisa até : . Parte do grupo 3. Tudo até o próximo delimitador. Talvez seja \(:\|$\) , mas como deveria terminar em : , bastaria.
  • E: \) Terminando o agrupamento de remoção.
  • F: Colocar o grupo de correspondências 1. Usuário + delimitador (es).
  • G: foo O que quer que seja inserido como cripta.
  • H: / Encerrando tudo. Optioanlly um /g para global, mas suponha que seja apenas uma vez.
por 28.11.2014 / 20:01
7

Você pode apenas alternar endereços aqui -

sed '/^[email protected]:{SHA512-CRYPT}/s/{[^:]*/REPLACE/'

Aqui, o comando s/// ubstitution é uma função do /regxp/ address e, portanto, a s/// ubstitution nem sequer é tentada, a menos que a primeira linha corresponda ao seu endereço pai.

Ou apenas com um único s/// :

sed 's/^\([email protected]:\){SHA512-CRYPT}[^:]*/REPLACE/'

Ou ancorando na linha de frente apenas se 123 não seguir imediatamente dois pontos:

sed 's/^\(\(.*:\)*[email protected]:\){SHA512-CRYPT}[^:]*/REPLACE/'

Embora eu certamente não esteja acostumado a sub-expressões complicadas, neste caso, tal coisa é desnecessária - eu geralmente prefiro o formulário de endereço quando posso obtê-lo - eu acho mais fácil de ler, é mais eficiente e totalmente portátil. É certo que, a um segundo olhar, parece que eu inicialmente superestimei a complicação inerente aqui.

Da mesma forma, você também pode dividir as referências anteriores e a substituição real como:

sed -e '
/^\([email protected]:\){SHA512-CRYPT}[^:]*/!b
s//REPLACE/
#other commands that can be sure to affect only a line matching the 1st address'

No exemplo acima, o endereço verifica uma correspondência por b ranching fora do script para qualquer linha ! não correspondente, mas também economiza o bit variável em para o próximo%.s/// ubstitution deve qualquer linha passar no teste de correspondência. Além disso, todos os comandos subsequentes também podem ser executados apenas em uma linha que corresponda ao endereço inicial.

E, claro, há a forma menos definitiva que especifica um contexto de função de correspondência com chaves:

sed -e '
/^[email protected]:{SHA512-CRYPT}/{
    s/{[^:]*/REPLACE/
    #other function commands
};/other match function/{
    #still more commands...
}'
    
por 29.11.2014 / 05:01
3

Usando awk :

awk -F':' '/^[email protected]/ {$2="NEWPASSWORDHERE"}1' OFS=':' infile

[email protected]:NEWPASSWORDHERE:::
[email protected]:{SHA512-CRYPT}$6$0vthg.LubtSCxRRK$MdTKNQ2Vk8ZW3XQXNXStt9rfr6fNa‌​XqPvZ0o9WJ8mW8y9ozE1pi8dYM8oQzwWa8ESGzEmJO6yT/tgi3ZEqAiE0:::
  • Eu usei awk com sua opção -F para definir dois pontos ( : ) como separador de campo e se o início da linha ( ^ ) com [email protected] substitua a coluna2 ( $2 ) por novo valor ( NEWPASSWODHERE ).

  • OFS=':' Altera o separador do campo de saída do espaço (por padrão) para dois pontos ( : ).

  • O 1 no final, permite a impressão por padrão.

por 28.11.2014 / 21:37