Como posso substituir o texto após uma palavra específica usando sed em vez de alterar a linha inteira?

0

Estou tentando substituir o texto após uma palavra específica, mas sed está alterando toda a linha. Extraia uma palavra depois de uma palavra específica

Arquivo de entrada: exemplo.txt

My Hostname:internal is valid.
some log file entries
some log file entries

Saída:

My Hostname:mmphate
some log file entries
some log file entries

Resultado esperado:

My Hostname:mmphate is valid.
some log file entries
some log file entries

Eu escrevi o script abaixo que está mudando todas as palavras depois de Hostname: Eu quero mudar apenas uma palavra depois de Hostname:

#!/usr/bin/env bash

HOST=$(curl -s 169.254.169.254/latest/meta-data/local-hostname)
while getopts ih opt
do
  case $opt in
  i)
    ;;
  h)
    sed -e "s/Hostname:.*/Hostname:$HOST/g" sample.txt
    echo "Updated Hostname: $HOST"
    ;;
  esac
done
    
por Mahesh Phate 23.03.2017 / 06:18

3 respostas

0

.* corresponde a tudo no restante da linha, então tudo é substituído. Se você quiser substituir tudo até o próximo espaço, então você precisa de [^ ] instead of '.

    
por 23.03.2017 / 07:38
0

Quando você realiza interpolações de aspas duplas em rhs de s/// , você precisa estar ciente de escape de proplery as entradas, pois elas podem ser especiais para sed e, portanto, resultar em um erro ou, pior ainda, sem erros, mas um resultado que foi totalmente involuntário. Considere, por exemplo, o que aconteceria se seu $HOST compreendesse um e comercial & ou um / .

# definitions
TAB='echo 'x' | tr 'x' '1''; # tab
SPC='echo 'x' | tr 'x' '0''; # space
eval "'echo 'n=qsq' | tr 'qs' '72''"; # newline

# construct regexes
s="[$SPC$TAB]";  # spc/tab regex
S="[^$SPC$TAB]"; # nonwhitespace regex

# perform the escape operation
esc() {
   set -- "${1//\/\\}" # escape backslash to prevent it from dissolving
   set -- "${1//\//\\/}" # escape forward slash to prevent from clashing with delimiters
   set -- "${1//&/\&}"   # escape ampersand since it has a specific meaning rhs of s//
   set -- "${1//\"/\\"}" # escape double quotes in an interpolation
   set -- "${1//$n/\$n}" # escape newlines
   printf '%s\n' "$@"
}

# grab the hostname
HOST=$(curl -s 169.254.169.254/latest/meta-data/local-hostname)

# escape hostname to enable it to be used seamlessly on the rhs of s///
host_esc=$(esc "$HOST")

# and then...
sed -e "s/\(${s}Hostname\):$S$S*/:$host_esc/g" sample.txt
    
por 23.03.2017 / 11:45
0

Seu problema não é reproduzível:

$ name="george"
$ echo "My Hostname:internal is valid." |sed "s/internal/$name/g"
My Hostname:george is valid.

Caso a palavra internal exista também nas entradas de log abaixo de My Hostname , você poderá usar algo assim:

$ sed -r "s/(My Hostname:)(internal)/$name/g" file4
My Hostname:george is valid.
internal log entry
log internal entry

Se você não tem GNU Sed ou seu sed não funciona como esperado por algum motivo, para substituições simples, você sempre pode alternar para perl , que funciona da mesma maneira em todos os lugares:

$ cat file4
My Hostname:internal is valid.
internal log entry
log internal entry

$ perl -pe "s/(My Hostname:)(internal)/$name/g" file4
My Hostname:george is valid.
internal log entry
log internal entry

Tanto o sed quanto o perl podem ser combinados com -i para edição em vigor, se necessário.

    
por 23.03.2017 / 13:10