使用 sed 在 linux 中查找以开头并替换的行 [重复]
Posted
技术标签:
【中文标题】使用 sed 在 linux 中查找以开头并替换的行 [重复]【英文标题】:Find line starts with and replace in linux using sed [duplicate] 【发布时间】:2018-10-09 02:03:36 【问题描述】:如何查找行开头并替换完整行?
文件输出:
xyz
abc
/dev/linux-test1/
代码:
output=/dev/sda/windows
sed 's/^/dev/linux*/$output/g' file.txt
我遇到以下错误:
sed: -e expression #1, char 9: unknown option to `s'
替换后预期的文件输出:
xyz
abc
/dev/sda/windows
【问题讨论】:
Replace whole line containing a string using sed、Replace whole line when match found with sed、Use slashes in sed replace 和 Delete using a different delimiter with Sed 的可能重复项 【参考方案1】:让我们一步一步来。
首先我们尝试将“dev”更改为“other”:
sed 's/dev/other/' file.txt
/other/linux-test1/
(省略其他行。)到目前为止,一切都很好。现在 "/dev/" => "/other/":
sed 's//dev///other//' file.txt
sed: 1: "s//dev///other//": bad flag in substitute command: '/'
啊,很困惑,我们将“/”用作命令分隔符和文字文本。所以我们使用不同的分隔符,比如'|':
sed 's|/dev/|/other/|' file.txt
/other/linux-test1/
很好。现在我们尝试替换整行:
sed 's|^/dev/linux*|/other/|' file.txt
/other/-test1/
它并没有替换整行...啊,在 sed 中,'*' 表示 前一个字符重复了任意次数。 所以我们在它前面加上 '.',这意味着任何字符:
sed 's|^/dev/linux.*|/other/|' file.txt
/other/
现在介绍变量:
sed 's|^/dev/linux.*|$output|' file.txt
$output
shell 没有扩展变量,因为单引号。我们改为双引号:
sed "s|^/dev/linux.*|$output|" file.txt
/dev/sda/windows
【讨论】:
【参考方案2】:这可能对你有用(GNU sed):
output="/dev/sda/windows"; sed -i '\#/dev/linux.*/#c'"$output" file
设置shell变量并将/dev/linux.*/
寻址的行改为它。
注意shell 变量需要插值,因此;
即变量可以单独设置在一行上。此外,sed 地址的分隔符必须更改,以免干扰地址,因此\#...#
,最后 shell 变量应该用双引号括起来以允许完全插值。
【讨论】:
【参考方案3】:我建议不要这样做。原因如下。
Sed 不是一种编程语言。它是一个流编辑器,具有一些外观和行为类似于语言的结构,但它在任意字符串操作、格式控制等方面提供的功能很少。
Sed 仅从文件或标准输入(也是文件)中获取数据。在您的 sed 脚本中嵌入字符串是在要求错误 - 像 s/re/$output/
这样的构造注定会在某个时候失败,几乎不管您在 sed 脚本中构建了什么变通方法。使此类 sed 命令发挥作用的最佳解决方案是在 sed 外部进行输入清理。
这让我想到......这可能是这项工作的错误工具,或者可能只是该工作工具集的一个组件。
您遇到的错误显然是因为您使用的 sed 命令被严重破坏了。替换命令是:
s/pattern/replacement/flags
但你正在运行的命令是:
s/^/dev/linux*/$output/g
您要搜索的模式是^
,即行首的空值。你的替换模式是dev
,那么你有一堆可能被解释为标志的文本。当您的搜索字符串包含与您用作替代命令选项分隔符的相同字符时,这显然不起作用。
在正则表达式和 sed 中,您可以转义。尽管s/^\/dev\/linux.*/$output/
可能会吸引您,但如果$output
包含斜线,您仍然会遇到困难。如果您将此脚本从 bash 提供给 sed,则可以使用 $output//\//\\\/
,但您无法在 sed 本身中处理这些转义。 Sed 没有变量。
在适当的编程语言中,您可以更好地分离变量内容和用于替换的命令。
output="/dev/sda/windows"
awk -v output="$output" '$1~/\/dev\/linux/ $0=output 1' file.txt
请注意,我在这里使用了$1
,因为在您的问题中,您的输入行(和输出)似乎在每行的开头都有一个空格。分配字段(位置)变量时,awk 会自动修剪前导和尾随空格。
或者您甚至可以在纯 bash 中执行此操作,无需使用外部工具:
output="/dev/sda/windows"
while read -r line; do
[[ "$line" =~ ^/dev/linux ]] && line="$output"
printf '%s\n' "$line"
done < file.txt
面对领先的空白,这个没有弹性。盐调味。
所以 .. 是的,你可以用 sed 做到这一点。但是,在 sed 中将命令组合在一起的方式使这样的事情变得有风险,尽管有可用的变通方法,例如将替换命令分隔符切换到另一个字符,但几乎可以肯定,使用其他工具会更好。
【讨论】:
以上是关于使用 sed 在 linux 中查找以开头并替换的行 [重复]的主要内容,如果未能解决你的问题,请参考以下文章