如何使用 sed 替换特定单词后的文本而不是更改整行?

如何使用 sed 替换特定单词后的文本而不是更改整行?

我试图替换特定单词后的文本,但sed正在更改整行。提取特定单词后的一个单词

输入文件:样本.txt

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

输出:

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

预期输出:

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

我编写了下面的脚本,该脚本在Hostname:我只想更改一个单词后更改所有单词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

答案1

当您对右旋s///需要注意对输入进行正确的转义,因为它们可能是特殊的sed,因此会导致错误,或者更糟糕的是,没有错误,但结果完全是意外的。例如,考虑一下如果您$HOST包含 & 符号&或会发生什么/

# definitions
TAB=`echo 'x' | tr 'x' '\011'`; # tab
SPC=`echo 'x' | tr 'x' '\040'`; # space
eval "`echo 'n=qsq' | tr 'qs' '\047\012'`"; # 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*/\1:$host_esc/g" sample.txt

答案2

.*与该行其余部分的所有内容匹配,因此所有内容都被替换。如果您想将所有内容替换到下一个空格,那么您需要[^ ] instead of。`

答案3

您的问题不可重现:

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

如果该词internal也存在于下面的日志条目中,My Hostname那么您可以使用如下内容:

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

如果您没有GNU Sedsed由于某种原因无法按预期工作,对于这种简单的替换,您可以随时切换到perl在任何地方都以相同方式工作的方法:

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

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

如果需要,sed 和 perl 都可以结合起来-i进行就地编辑。

相关内容