查找行开头并使用sed在linux中替换

时间:2018-04-28 10:53:07

标签: linux bash shell unix sed

如何查找行开头并替换完整行?

文件输出:

 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

3 个答案:

答案 0 :(得分:0)

这可能适合你(GNU sed):

output="/dev/sda/windows"; sed -i '\#/dev/linux.*/#c'"$output" file

设置shell变量并将/dev/linux.*/寻址的行更改为它。

N.B。 shell变量需要插值;,即变量可以自己设置在一行上。此外,必须更改sed地址的分隔符,以免干扰地址,因此\#...#,最后shell变量应该用双引号括起来以允许完全插值。

答案 1 :(得分:-1)

让我们采取一些小步骤。

首先我们尝试将“dev”改为“other”:

sed 's/dev/other/' file.txt
/other/linux-test1/

(省略其他部分。)到目前为止,这么好。现在“/ dev /”=> “/其他/”:

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 :(得分:-1)

我建议不这样做。这就是原因。

Sed不是一种编程语言。它是一个流编辑器,其中包含一些外观和行为类似于语言的构造,但它几乎不提供任意字符串操作,格式控制等。

Sed仅从文件或stdin(也是文件)中获取数据。在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中组合在一起会产生类似风险的问题,尽管可以使用诸如将替换命令分隔符切换到另一个角色的可用解决方法,但使用其他工具几乎肯定会更好。