Unix sed就地编辑文件

Unix sed就地编辑文件,unix,sed,solaris,Unix,Sed,Solaris,我试图找出是否可以在单个sed命令中编辑文件,而不必手动将编辑的内容流式传输到新文件中,然后将新文件重命名为原始文件名。我尝试了-I选项,但我的Solaris系统说-I是非法选项。还有其他方法吗?将编辑的内容流式传输到新文件中,然后在幕后重命名 例如: sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename 及 在macOS上。支持在位编辑文件的-i选项的sed版本写入临时文件,然后重命名文件 或者,您可以只使用ed。例如,要将

我试图找出是否可以在单个sed命令中编辑文件,而不必手动将编辑的内容流式传输到新文件中,然后将新文件重命名为原始文件名。我尝试了
-I
选项,但我的Solaris系统说
-I
是非法选项。还有其他方法吗?

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

例如:

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


在macOS上。

支持在位编辑文件的
-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'文件
,您可以执行
内联文件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
#/垃圾箱/垃圾箱
英寸=1美元
转移
陷阱“rm-f”$tmp“0
tmp=$(mktemp)
“$tmp”&&cat“$tmp”>“$IN”#保留硬链接

应该适合大多数使用。

您没有指定要使用的shell,但是对于zsh,您可以使用
=()
构造来实现这一点。大致如下:

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

=()
()
类似,但创建了一个临时文件,当
cp
终止时,该文件会自动删除。

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

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

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

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

三通法

sed'/regex/'| tee
修补方法

sed'/regex/'| diff-p/dev/stdin | patch
更新:

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

修补程序不需要知道要访问哪个文件,因为它位于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

以下内容在我的mac上运行良好

sed -i.bak 's/foo/bar/g' sample
我们正在示例文件中将foo替换为bar。原始文件的备份将保存在sample.bak中

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

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

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

sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
sed-i'-e“s/STRING\u TO\u REPLACE/STRING\u TO\u REPLACE\u IT/g”

这是因为在OSX版本的
sed
上,
-i
选项需要一个
扩展名
参数,因此您的命令实际上被解析为
扩展名
参数,文件路径被解释为命令代码。源代码:

非常好的示例。我曾遇到过在适当位置编辑许多文件和-i选项似乎是在find命令中使用它的唯一合理解决方案。下面是在每个文件的第一行前面添加“version:”的脚本:

find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;
支持就地编辑。从
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.txt
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt
应保留所有硬链接,因为输出会被定向回以覆盖原始文件的内容,并且避免了对sed特殊版本的任何需要。

如果要替换相同数量的字符,请在仔细阅读后。。。 您还可以使用重定向操作符
打开文件进行读写:

sed 's/foo/bar/g' file 1<> file
sed's/foo/bar/g'文件1文件
现场观看:

$ 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
$cat文件
你好
我在这里#见“这里”
$sed's/here/away/'file 1 file#运行'sed'命令
$cat文件
你好
我不在,这条线路现在改了
发件人:

重定向操作符

[n]<>word
[n]字
导致为其打开名为word扩展名的文件 读取和写入文件描述符n或文件描述符0 如果未指定n。如果文件不存在,则创建该文件


就像Moneypenny在Skyfall中说的:“有时候老办法是最好的。” 金凯德后来也说了类似的话

$ printf ',s/false/true/g\nw\n' | ed {YourFileHere}
快乐编辑到位。 添加了“\nw\n”来写入文件。对于延迟答复请求表示歉意。

您可以使用vi

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

至少对我来说是这样的,所以我不必担心。那么,你可以试着在你的系统上编译GNU。例如:
sed-i“s/STRING\u to\u REPLACE/STRING\u to\u REPLACE\u it/g”
这比perl解决方案要好。不知何故,它不会创建任何.swap文件……谢谢!@math:它会创建,但可能在其他地方或更短的时间?
-i
在gnu sed中是一个选项,但在标准sed中不是。但是,它将内容流式传输到一个新文件,然后重命名该文件,因此它不是您想要的。实际上,它是w我想要的帽子,我只是想
vi -c '%s/foo/bar/g' my.txt -c 'wq'