sed编辑文件到位

我试图找出是否有可能编辑一个单一的sed命令中的文件,而无需手动stream编辑的内容到一个新的文件,然后将新文件重命名为原始文件名。 我尝试了-i选项,但是我的Solaris系统表示-i是非法的选项。 有不同的方法吗?

-i选项将编辑后的内容传输到新文件中,然后在幕后对其进行重命名。

例:

 sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename 

在一个sed没有编辑文件的系统上,我认为更好的解决scheme是使用perl

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

虽然这确实会创build一个临时文件,但由于已经提供了一个空的后缀/扩展名,它将replace原来的文件。

请注意,在OS X上运行此命令时,可能会出现奇怪的错误,如“无效的命令代码”或其他奇怪的错误。 要解决这个问题,请尝试

 sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file> 

这是因为在sed的OSX版本中, -i选项需要一个extension参数,所以您的命令实际上被parsing为extension参数,文件path被解释为命令代码。 来源: https : //stackoverflow.com/a/19457213

以下工作正常我的Mac

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

我们用示例文件中的barreplacefoo。 原始文件的备份将保存在sample.bak中

对于没有备份的内联编辑,请使用以下命令

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

有一件事要注意, sed不能单独编写文件,因为sed的唯一目的是充当“stream”(即stdin,stdout,stderr和其他>&n缓冲区,套接字等的pipe道)的编辑器。 。 考虑到这一点,您可以使用另一个命令tee将输出写回到文件中。 另一种select是通过将内容传送到diff来创build一个补丁。

三通法

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

补丁方法

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

更新:

此外,请注意,修补程序将从diff输出的第1行获得文件更改:

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

 $ 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 

sed做你想做的事是不可能的。 甚至支持用于编辑文件的-i选项的sed版本也完全符合您明确声明不需要的内容:它们写入临时文件,然后重命名文件。 但也许你可以使用ed 。 例如,要将文件file.txt所有出现的foo更改为bar ,可以执行以下操作:

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

语法类似于sed ,但是肯定不完全一样。

但也许你应该考虑为什么你不想使用一个重命名的临时文件。 即使你没有支持sed-i ,你也可以很容易地写一个脚本来为你做这个工作。 而不是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 

应该足够用于大多数用途。

sed支持就地编辑。 从man sed

 -i[SUFFIX], --in-place[=SUFFIX] edit files in place (makes backup if extension supplied) 

例如

假设你有一个带有文本的文件hello.txt

 hello world! 

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

 sed -i.bak 's/hello/bonjour' hello.txt 

你将会得到两个文件: hello.txt和内容:

 bonjour world! 

和旧的内容hello.txt.bak

如果你不想保留一个副本,只是不要传递扩展参数。

 mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt 

应该保留所有的硬链接,因为输出被引导回覆盖原文件的内容,并且避免需要特殊版本的sed。

如果您正在replace相同数量的字符,并仔细阅读“就地”编辑文件后 …

您也可以使用redirect操作符<>来打开文件来读取和写入:

 sed 's/foo/bar/g' file 1<> file 

现场观看:

 $ 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 

从Bash参考手册→3.6.10读取和写入打开文件描述符 :

redirect操作符

 [n]<>word 

导致名称为扩展名的文件在文件描述符n上读取和写入,如果未指定n,则在文件描述符0上打开。 如果该文件不存在,则会创build该文件。

你可以用vi

 vi -c '%s/foo/bar/g' my.txt -c 'wq' 

你没有指定你正在使用的shell,但是使用zsh你可以使用=( )结构来实现这一点。 有些东西是:

 cp =(sed ... file; sync) file 

=( )类似于>( )但创build一个临时文件,当cp终止时它会被自动删除。

就像Moneypenny在Skyfall中说的那样:“有时旧的方式是最好的。 Kincade稍后说了类似的话。

$ printf',s / false / true / g'| ed {YourFileHere}

快乐的编辑到位。

非常好的例子。 我面临着编辑许多文件的挑战,-i选项似乎是在find命令中使用它的唯一合理解决scheme。 这里的脚本在每个文件的第一行前加上“version:”:

 find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;