.*
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
'.
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
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
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.
Tags text-processing sed linux