我尝试了sed -i,但我的Solaris系统显示-i是一个非法选项。有其他方法吗?
-i
选项将编辑的内容流式传输到一个新文件中,然后在幕后重命名它。
示例:
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
如果您使用的是 macOS,则需要执行以下操作:
sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
sed -i "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
- Thales Ceolinsed -i -e 's,STRING with SPACES,STRING to REPLACE with,g' filename
。也就是说,逗号,
的使用很重要,而不是斜杠 /
。请注意,我会尽力使翻译通俗易懂,但不会添加任何解释或其他内容。 - Oleg Kokorin如果系统上的 sed
没有原地编辑文件的功能,我认为更好的解决方案是使用 perl
:
perl -pi -e 's/foo/bar/g' file.txt
虽然这会创建一个临时文件,但由于提供了一个为空的原地后缀/扩展名,它会替换原始文件。
sed 's/foo/bar/g' file.txt > file.tmp && mv file.tmp file.txt
。仅仅因为原地编辑使用临时文件进行重命名,并不意味着当选项不可用时,他/她必须执行手动重命名。还有其他工具可以做到他/她想要的事情,Perl是显而易见的选择。这不是对原始问题的答案吗? - Stevesed
实现他想要的结果。实际上,这个问题非常好,但是由于一些人不能阅读手册或不能真正阅读Stack Overflow上的问题,它的价值已经被削弱了。 - Stevesed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
这是因为在OSX版本的sed
上,-i
选项需要一个extension
参数,所以你的命令实际上被解释为extension
参数,而文件路径则被解释为命令代码。来源:https://dev59.com/tmIk5IYBdhLWcg3wPL_R#19457213brew install gnu-sed
以及PATH
,您可以使用GNU版本的sed。谢谢您提到这点,这确实令人费解。 - Doug以下内容在我的Mac上运行良好。
sed -i.bak 's/foo/bar/g' sample
我们正在样本文件中将“foo”替换为“bar”。原始文件的备份将保存在sample.bak中。
如需在不进行备份的情况下进行内联编辑,请使用以下命令
sed -i'' 's/foo/bar/g' sample
需要注意的一点是,sed
不能单独写入文件,因为它的唯一目的是作为“流”(即标准输入、标准输出、标准错误和其他>&n
缓冲区、套接字等)的编辑器。有了这个想法,您可以使用另一个命令tee
将输出写回文件。另一种选择是通过将内容传输到diff
中创建补丁。
Tee方法
sed '/regex/' <file> | tee <file>
补丁方法
sed '/regex/' <file> | diff -p <file> /dev/stdin | patch
更新:
另外,请注意,补丁将使文件从差异输出的第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
/dev/stdin
不存在,因此您必须用一个单破折号'-'替换/dev/stdin
,以便以下命令可以正常工作:$ sed 's/oo/u/' fubar | diff -p fubar -
和 $ sed 's/oo/u/' fubar | diff -p fubar - | patch
。 - Jim Raden支持使用-i
选项在原地编辑文件的sed
版本会先写入一个临时文件,然后再将文件重命名。
或者,您可以直接使用ed
。例如,要将文件file.txt
中所有出现的foo
更改为bar
,可以执行以下操作:
echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt
语法类似于sed
,但并不完全相同。
即使您没有支持sed -i
的选项,您仍然可以轻松编写一个脚本来完成工作。您可以使用inline file sed 's/foo/bar/g'
替代sed -i 's/foo/bar/g' file
。这样的脚本很容易编写。例如:
#!/bin/sh
IN=$1
shift
trap 'rm -f "$tmp"' 0
tmp=$( mktemp )
<"$IN" "$@" >"$tmp" && cat "$tmp" > "$IN" # preserve hard links
对于大多数情况来说应该是足够的。
inline
并按照上述描述调用它:inline inputfile sed 's/foo/bar/g'
。 - William Purselled
的答案真正地做到了原地修改。这是我第一次需要使用 ed
。谢谢。一个小优化是使用 echo -e ",s/foo/bar/g\012 w"
或者 echo $',s/foo/bar/g\012 w'
,如果 shell 允许的话,可以避免额外的 tr
调用。 - akostadinoved
仍然保留硬链接。你的情况可能会有所不同。 - William Pursell您可以使用vi编辑器
vi -c '%s/foo/bar/g' my.txt -c 'wq'
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
文件。
如果您不想保留副本,只需不传递扩展参数即可。
你也可以使用重定向运算符<>
来打开文件进行读写:
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 打开文件描述符进行读写:
The redirection operator
[n]<>word
causes the file whose name is the expansion of word to be opened for both reading and writing on file descriptor n, or on file descriptor 0 if n is not specified. If the file does not exist, it is created.
正如《007:大破天幕杀机》中蒙尼彭尼所说:“有时候老方法最好。” 后来金凯德也说了类似的话。
$ printf ',s/false/true/g\nw\n' | ed {YourFileHere}
愉快地进行原地编辑。 添加了'\nw\n'来写入文件。 对于回答请求的延迟表示歉意。
|
将字符管道输入而不是打开ed并键入这些内容。@MattMontag - Ari Sweedler\n
结尾。[range]s/<old>/<new>/<flag>是替换命令的形式——这种范例在许多其他文本编辑器中仍然存在(好吧,vim是ed的直接后代)。无论如何,g
标志代表“全局”,意味着“每一行上你查看到的每一个实例”。范围3,5
查看第3-5行。,5
查看StartOfFile-5,3,
查看第3行-EndOfFile,,
查看StartOfFile-EndOfFile。全局替换命令在每一行上将“false”替换为“true”。然后,输入写入命令w
。 - Ari Sweedler
-i
是 gnu sed 中的一个选项,但不属于标准 sed。使用该选项会将内容流式传输到新文件,然后将文件重命名,这可能不是您想要的。 - William Pursell