我试图找出是否可以在单个sed命令中编辑一个文件,而无需手动将编辑的内容流到一个新文件中,然后将新文件重命名为原始文件名。

我尝试了-i选项,但是Solaris系统说-i是非法选项。还有别的办法吗?


当前回答

如果你想替换包含'/'的sting,你可以使用'?'。例如,将所有*.py文件的“/usr/local/bin/python”替换为“/usr/bin/python3”。

找到。/usr/bin/python ?/usr/bin/python3?G ' {} \;

其他回答

如果你想替换包含'/'的sting,你可以使用'?'。例如,将所有*.py文件的“/usr/local/bin/python”替换为“/usr/bin/python3”。

找到。/usr/bin/python ?/usr/bin/python3?G ' {} \;

在一个系统中,sed没有编辑文件的能力,我认为更好的解决方案是使用perl:

perl -pi -e 's/foo/bar/g' file.txt

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

下面的程序在我的mac上运行良好

sed -i.bak 's/foo/bar/g' sample

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

要编辑内联而不备份,请使用以下命令

sed -i'' 's/foo/bar/g' sample

支持-i选项就地编辑文件的sed版本写入临时文件,然后重命名该文件。

或者,你可以只使用ed。例如,要更改文件file.txt中所有出现的foo为bar,你可以这样做:

echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt

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

即使没有-i支持sed,也可以很容易地编写一个脚本来完成这项工作。而不是sed -i 's/foo/bar/g'文件,你可以做内联文件sed 's/foo/bar/g'。这样的脚本编写起来很简单。例如:

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

对于大多数用途应该是足够的。

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

三通法

sed '/regex/' <file> | tee <file>

修补方法

sed '/regex/' <file> | diff -p <file> /dev/stdin | patch

更新:

另外,请注意patch将从diff输出的第一行获取要更改的文件:

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

$ echo foobar | tee fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin
*** fubar   2014-03-15 18:06:09.000000000 -0500
--- /dev/stdin  2014-03-15 18:06:41.000000000 -0500
***************
*** 1 ****
! foobar
--- 1 ----
! fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch
patching file fubar