sed编辑文件到位

amp*_*ent 264 unix solaris sed

我试图找出是否可以在单个sed命令中编辑文件,而无需手动将已编辑的内容流式传输到新文件中,然后将新文件重命名为原始文件名.我尝试了这个-i选项,但我的Solaris系统说这-i是一个非法的选择.有不同的方式吗?

cho*_*oba 409

-i选项将编辑的内容流式传输到新文件中,然后在幕后重命名.

例:

sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
Run Code Online (Sandbox Code Playgroud)

sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
Run Code Online (Sandbox Code Playgroud)

macOS上.

  • 对于mac来说+1,这可能是第三次(在过去的4年里)我忘记了它需要额外的引号,不得不返回到这篇文章。但我要辩解一下,95% 的时间我都使用我的 Mac 来 ssh 到 Linux 机器上。 (5认同)
  • 至少它是为我做的所以我没有必要 (3认同)
  • 例如:`sed -i"s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g"<file>` (3认同)
  • @maths:确实如此,但也许在其他地方或更短的时间? (3认同)
  • 您可能会尝试在您的系统上编译GNU sed. (2认同)
  • 这比perl解决方案更好.不知怎的,它不会创建任何.swap文件....谢谢! (2认同)
  • 在Yocto构建系统上,以下示例工作:`sed -i -e's,STRING带空格,STRING替换为,g'filename`-即重要的是逗号`,`而不是斜杠`/` (2认同)
  • `-i` 的一个主要好处是它比 shell 重定向快得多。在我的机器上,写入旋转磁盘时,速度从 5MB/s 升至约 12MB/s。 (2认同)

Ste*_*eve 70

在一个sed无法编辑文件的系统上,我认为更好的解决方案是使用perl:

perl -pi -e 's/foo/bar/g' file.txt
Run Code Online (Sandbox Code Playgroud)

虽然这确实创建了一个临时文件,但它会替换原始文件,因为提供了一个空的就位后缀/扩展名.

  • 它不仅创建了一个临时文件,还打破了硬链接(例如,它不是更改文件的内容,而是用一个同名的新文件替换该文件.)有时这是所需的行为,有时它是可以接受,但是当有多个链接到文件时,它几乎总是错误的行为. (14认同)
  • @DwightSpencer:我相信所有没有Perl的系统都会被破坏.当一个人想要提升权限并且必须使用`sudo`时,单个命令胜过命令链.在我看来,问题是如何避免手动创建和重命名临时文件,而无需安装最新的GNU或BSD`sed`.只需使用Perl. (3认同)
  • @PetrPeller:真的吗?如果你仔细阅读这个问题,你就会明白OP正试图避免像`sed'/ foo/bar/g'file.txt> file.tmp && mv file.tmp file.txt`这样的东西.仅仅因为就地编辑使用临时文件进行重命名,并不意味着当选项不可用时他/她必须执行手动重命名.还有其他工具可以做他/她想要的工作,Perl是显而易见的选择.这怎么不是原始问题的答案? (3认同)
  • @EdwardGarson:IIRC,Solaris附带Perl但不附带Python或Ruby.就像我之前所说的那样,OP无法使用Solaris sed实现预期的结果. (3认同)
  • 并非所有系统都有 Perl,这就是管道发挥作用的地方。请参阅下面我的回答。 (2认同)
  • @a_arias:您是对的;他做到了。但是他无法使用Solaris`sed`实现他想要的。这个问题实际上是一个非常好的问题,但是由于无法阅读手册页或不愿意在这里SO实际阅读问题的人而降低了其价值。 (2认同)

小智 52

请注意,在OS X上,运行此命令时可能会出现"无效命令代码"或其他奇怪错误等奇怪错误.要解决此问题,请尝试

sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
Run Code Online (Sandbox Code Playgroud)

这是因为在OSX版本中sed,该-i选项需要一个extension参数,因此您的命令实际上被解析为extension参数,文件路径被解释为命令代码.资料来源:https://stackoverflow.com/a/19457213

  • 这是 OS X 的另一个奇怪之处。幸运的是,“brew install gnu-sed”和“PATH”将允许您使用 GNU 版本的 sed。感谢您提及;绝对令人头疼。 (2认同)

min*_*s23 23

以下在我的Mac上工作正常

sed -i.bak 's/foo/bar/g' sample
Run Code Online (Sandbox Code Playgroud)

我们正在用示例文件中的bar替换foo.原始文件的备份将保存在sample.bak中

要在没有备份的情况下编辑内联,请使用以下命令

sed -i'' 's/foo/bar/g' sample
Run Code Online (Sandbox Code Playgroud)


Dwi*_*cer 15

有一点需要注意,sed不能自己编写文件,因为sed的唯一目的是充当"流"的编辑器(即stdin,stdout,stderr和其他>&n缓冲区,套接字等的流水线).考虑到这一点,您可以使用另一个命令tee将输出写回文件.另一种选择是创建一个补丁,将内容管道化diff.

Tee方法

sed

补丁方法

>&n

更新:

另外,请注意补丁将从diff输出的第1行获取文件:

补丁不需要知道要访问哪个文件,因为这是在diff的输出的第一行中找到的:

sed '/regex/' <file> | tee <file>
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,这些解决方案依赖于特定的缓冲行为。我怀疑对于较大的文件,这些文件可能会在 sed 读取时损坏,文件可能会通过 patch 命令开始在下面进行更改,甚至更糟糕的是,通过将截断文件的 tee 命令。实际上我不确定“patch”是否也不会被截断。我认为将输出保存到另一个文件,然后“cat”到原始文件中会更安全。 (4认同)
  • `/dev/stdin 2014-03-15`,*1 月 7 日回答* - 你是时间旅行者吗? (3认同)

Wil*_*ell 10

你不可能做你想做的事sed.甚至sed那些支持-i编辑文件的选项的版本也完全按照您明确声明的不需要的方式执行:它们写入临时文件然后重命名该文件.但也许你可以使用ed.例如,改变所有出现foobar文件中file.txt,你可以这样做:

echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt
Run Code Online (Sandbox Code Playgroud)

语法类似sed,但肯定不完全相同.

但也许你应该考虑为什么你不想使用重命名的临时文件.即使您没有-i支持sed,也可以轻松编写脚本来为您完成工作.而不是sed -i 's/foo/bar/g' file,你可以做到inline file sed 's/foo/bar/g'.写这样一个脚本是微不足道的.例如:

#!/bin/sh -e
IN=$1
shift
trap 'rm -f $tmp' 0
tmp=$( mktemp )
<$IN "$@" >$tmp && cat $tmp > $IN  # preserve hard links
Run Code Online (Sandbox Code Playgroud)

应该适合大多数用途.

  • 我会称它为"inline"并按上述方式调用它:`inline inputfile sed's/foo/bar/g'` (2认同)
  • 哇,“ed”只是真正就地回答。我第一次需要“ed”。谢谢。一点优化是使用 `echo -e ",s/foo/bar/g\012 w"` 或 `echo $',s/foo/bar/g\012 w'`,其中 shell 允许避免额外的 ` tr` 调用。 (2认同)
  • ed并没有真正就地进行修改。从`strace`输出,GNU`ed`创建一个临时文件,将更改写入临时文件,然后重写整个原始文件,保留硬链接。从“ truss”输出中,Solaris 11“ ed”还使用了一个临时文件,但是在使用“ w”命令保存后将其重命名为原始文件名,这会破坏所有硬链接。 (2认同)

men*_*nch 10

你可以使用vi

vi -c '%s/foo/bar/g' my.txt -c 'wq'
Run Code Online (Sandbox Code Playgroud)


Ser*_* A. 7

sed支持就地编辑.来自man sed:

-i[SUFFIX], --in-place[=SUFFIX]

    edit files in place (makes backup if extension supplied)
Run Code Online (Sandbox Code Playgroud)

示例:

假设您有一个hello.txt包含文本的文件:

hello world!
Run Code Online (Sandbox Code Playgroud)

如果要保留旧文件的备份,请使用:

sed -i.bak 's/hello/bonjour' hello.txt
Run Code Online (Sandbox Code Playgroud)

您将得到两个文件:hello.txt内容:

bonjour world!
Run Code Online (Sandbox Code Playgroud)

hello.txt.bak旧的内容.

如果您不想保留副本,请不要传递扩展参数.

  • OP特别提到他的平台不支持这个(流行的但是)非标准选项. (3认同)

fed*_*qui 5

如果您要替换相同数量的字符并仔细阅读文件的“就地”编辑...

您还可以使用重定向运算符<>打开文件进行读写:

sed 's/foo/bar/g' file 1<> file
Run Code Online (Sandbox Code Playgroud)

现场观看:

$ cat file
hello
i am here                           # see "here"
$ sed 's/here/away/' file 1<> file  # Run the `sed` command
$ cat file
hello
i am away                           # this line is changed now
Run Code Online (Sandbox Code Playgroud)

来自Bash 参考手册?3.6.10 打开文件描述符进行读写

重定向运算符

[n]<>word
Run Code Online (Sandbox Code Playgroud)

导致名称为 word 扩展的文件被打开,以便在文件描述符 n 上读取和写入,如果未指定 n,则在文件描述符 0 上打开。如果文件不存在,则创建它。

  • 这篇博文解释了为什么不应该使用这个答案。http://backreference.org/2011/01/29/in-place-editing-of-files/ (3认同)