使用Sed替换包含字符串的整行


319

我有一个文本文件,其中有一个特定的行,例如

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

我需要将上面的整行替换为

This line is removed by the admin.

搜索关键字是 TEXT_TO_BE_REPLACED

我需要为此编写一个shell脚本。我该如何使用sed呢?


@Scharron我尝试了sed -rne's /(TEXT_TO_BE_REPLACED)\ s + \ w + / \ 1 yyy / xxx',但是如果存在yyy,那就用字符串中的xxx替换yyy。就我而言,文本不固定...我所拥有的只是TEXT_TO_BE_REPLACED。
拉胡尔2012年

这不是有效的sed表达式。确定要使用sed吗?具有良好正则表达式的任何编程语言都可以为您替代(搜索子函数)。这比自己了解sed容易得多
Scharron 2012年

@Scharron好吧,它是用shell脚本完成的,所以我猜sed是我最好的选择。
拉胡尔2012年

Answers:


483

您可以使用change命令替换整行,并使用该-i标志就地进行更改。例如,使用GNU sed:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

4
请注意,在c \之前需要一个空格。我刚刚进行了编辑以添加此内容。
马库斯·唐宁

27
@MarcusDowning GNU的sed并没有要求空间; 它可以像最初发布的一样正常。如果您的特定sed需要空格,则一定要注意哪个sed不兼容,并添加必要的调用作为注释。但是,请不要在可接受的答案中更改工作代码。
Todd A. Jacobs 2014年

7
如何使用变量代替文本“ This ...”?如果我将其替换为$ variable,它不会显示其内容,但会显示变量名称。
2014年

18
c\ 直接在变量后面跟随时有一个问题:…c\$VAR…反斜杠将使美元转义。在这种情况下,我(Ubuntu 15.10上的bash / sed)不得不写…c\\$VAR…
1

6
在Mac上使用:sed -i '' '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo; (当第一个参数为空时,它将编辑文件中的文件,否则创建备份)
AndreDurao

152

您需要在.*前后使用通配符()替换整行:

sed 's/.*TEXT_TO_BE_REPLACED.*/This line is removed by the admin./'

谢谢,让我的工作正常了:sed's /.* <表达式>。* / <表达式> SE_LABEL = ABC <表达式> / g'MYR2.xml> test.txt
Nasri Najib

9
这可以在Mac OS X Yosemite上工作,但我使用-i和-e标志的情况如下:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Kent Bull

1
@KentJohnson我认为您的命令中的引号不匹配。
HashHazard

@MBarnett你是对的,我应该在这里用两个双引号。
肯特·布尔

2
只是为了完整的信息。要使其-i
就位,

20

接受的答案对我不起作用有以下几个原因:

  • 我的sed版本不喜欢-i扩展名为零
  • c\命令的语法很奇怪,我无法使其正常工作
  • 我没有意识到我的某些问题来自未转义的斜线

因此,这是我想出的解决方案,我认为该解决方案适用于大多数情况:

function escape_slashes {
    sed 's/\//\\\//g' 
}

function change_line {
    local OLD_LINE_PATTERN=$1; shift
    local NEW_LINE=$1; shift
    local FILE=$1

    local NEW=$(echo "${NEW_LINE}" | escape_slashes)
    sed -i .bak '/'"${OLD_LINE_PATTERN}"'/s/.*/'"${NEW}"'/' "${FILE}"
    mv "${FILE}.bak" /tmp/
}

因此,示例用法解决了这个问题:

change_line "TEXT_TO_BE_REPLACED" "This line is removed by the admin." yourFile

18

上面的答案:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

如果替换字符串/行不是变量,则可以正常工作。

问题是在Redhat 5 \c越狱后$。双重\\也不起作用(至少在Redhat 5上)。

通过命中和尝试,我发现如果替换字符串/行仅是一行,则\after c是多余的。因此,我没有\在之后使用c,而是将变量用作单个替换行,这很令人高兴。

代码如下所示:

sed -i "/TEXT_TO_BE_REPLACED/c $REPLACEMENT_TEXT_STRING" /tmp/foo

请注意使用双引号而不是单引号。


您仍可以像这样使用单引号:sed -i'/ TEXT_TO_BE_REPLACED / c'“ $ VARIABLE”“ / tmp / foo
Alistair McIntyre,

4

到目前为止,所有提供的答案都假定您对要替换的文本有所了解,这很有意义,因为这就是OP的要求。我提供的答案是假设您对要替换的文本一无所知,并且文件中可能有单独的一行,具有与您要替换的内容相同或相似的内容。此外,假设您知道要替换的行的行号。

下面的示例演示通过特定的行号删除或更改文本:

# replace line 17 with some replacement text and make changes in file (-i switch)
# the "-i" switch indicates that we want to change the file. Leave it out if you'd
#   just like to see the potential changes output to the terminal window.
# "17s" indicates that we're searching line 17
# ".*" indicates that we want to change the text of the entire line
# "REPLACEMENT-TEXT" is the new text to put on that line
# "PATH-TO-FILE" tells us what file to operate on
sed -i '17s/.*/REPLACEMENT-TEXT/' PATH-TO-FILE

# replace specific text on line 3
sed -i '3s/TEXT-TO-REPLACE/REPLACEMENT-TEXT/'

3

用于配置文件的操作

我想出了这个受skensell回答启发的解决方案

configLine [searchPattern] [replaceLine] [filePath]

它会:

  • 创建文件(如果不存在)
  • 替换searchPattern匹配的整行(所有行)
  • 如果找不到模式,则在文件末尾添加replaceLine

功能:

function configLine {
  local OLD_LINE_PATTERN=$1; shift
  local NEW_LINE=$1; shift
  local FILE=$1
  local NEW=$(echo "${NEW_LINE}" | sed 's/\//\\\//g')
  touch "${FILE}"
  sed -i '/'"${OLD_LINE_PATTERN}"'/{s/.*/'"${NEW}"'/;h};${x;/./{x;q100};x}' "${FILE}"
  if [[ $? -ne 100 ]] && [[ ${NEW_LINE} != '' ]]
  then
    echo "${NEW_LINE}" >> "${FILE}"
  fi
}

疯狂的退出状态魔术来自https://stackoverflow.com/a/12145797/1262663


2
bash-4.1$ new_db_host="DB_HOSTNAME=good replaced with 122.334.567.90"
bash-4.1$ 
bash-4.1$ sed -i "/DB_HOST/c $new_db_host" test4sed
vim test4sed
'
'
'
DB_HOSTNAME=good replaced with 122.334.567.90
'

它工作正常


1

在我的makefile文件中,我使用以下命令:

@sed -i '/.*Revision:.*/c\'"`svn info -R main.cpp | awk '/^Rev/'`"'' README.md

PS:请不要忘记-i实际上会更改文件中的文本...因此,如果您定义为“修订”的模式将更改,那么您还将更改要替换的模式。

输出示例:

John Doe撰写的Abc-Project

修订:1190

因此,如果您将模式设置为“修订版:1190”,则显然与您仅将其定义为“修订版:”不同...


1
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

find_replace文件包含2列,c1具有匹配的模式,c2具有替换,sed循环替换每一行,其中包含变量1的模式之一


不,这在很多方面都是错误的。sed使用包含您要执行的所有替换的脚本文件运行一次。sed -i反复在同一个文件上运行是一种可怕的反模式。
Tripleee '18

0

与上面的类似。

sed 's/[A-Za-z0-9]*TEXT_TO_BE_REPLACED.[A-Za-z0-9]*/This line is removed by the admin./'

3
改变FOO=TEXT_TO_BE_REPLACEDFOO=This line ...使不符合规范。
詹斯(Jens)

是的。我们的要求是将整个行替换为“该行已被管理员删除”。如果找到密钥模式“ TEXT_TO_BE_REPLACED”。上面的命令令人满意。如果我的理解是错误的,请纠正我。.@Jens
Annapureddy Hari

@AnnapureddyHari如果搜索字符串之前或之后的文本中除了A-Za-z0-9之外还包含其他任何内容,则此答案不起作用。正如詹斯指出的那样,如果存在等号则失败。“ FOO =”部分将保留;您尚未替换整行。此代码是关于文件中可能存在的内容的短视记录。如果您的意思是通配符,则应输入通配符,如Thor的答案所示。
msouth,2016年

0

下面的命令为我工作。哪个正在使用变量

sed -i "/\<$E\>/c $D" "$B"

但是我的新要求是在替换时对SKIP注释(以#开头)行。当我们替换完整行时,这也将替换注释行,并且您最终将获得重复的属性。如果有人对此有解决方案,请告诉我。
Ritesh Borkar

-1

我经常使用正则表达式来提取数据从我刚才使用的替换文字报价文件\"//什么:-)

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.