我试图找出是否可以在单个sed命令中编辑文件而不用 手动 将已编辑的内容流式传输到新文件中,然后重命名新文件到原始文件名。我尝试了-i
选项,但我的Solaris系统说-i
是非法选项。有不同的方式吗?
答案 0 :(得分:350)
-i
option将已编辑的内容流式传输到新文件中,然后在幕后重命名。
示例:
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
和
sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
在 macOS 上。
答案 1 :(得分:68)
在sed
无法编辑文件的系统上,我认为更好的解决方案是使用perl
:
perl -pi -e 's/foo/bar/g' file.txt
虽然这会创建一个临时文件,但它会替换原始文件,因为已经提供了一个空的就位后缀/扩展名。
答案 2 :(得分:46)
请注意,在OS X上,您可能会遇到奇怪的错误,例如"无效的命令代码"或运行此命令时的其他奇怪错误。要解决此问题,请尝试
sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
这是因为在sed
的OSX版本上,-i
选项需要extension
参数,因此您的命令实际上被解析为extension
参数和文件路径被解释为命令代码。资料来源:https://stackoverflow.com/a/19457213
答案 3 :(得分:21)
以下在我的Mac上运行正常
sed -i.bak 's/foo/bar/g' sample
我们正在用示例文件中的bar替换foo。原始文件的备份将保存在sample.bak
中要在没有备份的情况下编辑内联,请使用以下命令
sed -i'' 's/foo/bar/g' sample
答案 4 :(得分:11)
有一点需要注意,sed
无法自行编写文件,因为sed的唯一目的是充当“流”的编辑器(即stdin,stdout,stderr和其他{{的管道。 1}}缓冲区,套接字等)。考虑到这一点,您可以使用另一个命令>&n
将输出写回文件。另一个选择是创建一个补丁,将内容传递给tee
。
Tee方法
diff
补丁方法
sed '/regex/' <file> | tee <file>
更新:
另外,请注意补丁将从diff输出的第1行获取文件:
Patch不需要知道要访问哪个文件,因为这是在diff的输出的第一行中找到的:
sed '/regex/' <file> | diff -p <file> /dev/stdin | patch
答案 5 :(得分:10)
使用sed
无法执行您想要的操作。甚至版本的sed
支持用于编辑文件的-i
选项也完全按照您明确声明的方式执行操作:它们写入临时文件然后重命名该文件。但也许你可以使用ed
。例如,要将文件foo
中所有bar
更改为file.txt
,您可以执行以下操作:
echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt
语法类似于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
应该适合大多数用途。
答案 6 :(得分:7)
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
包含旧内容。
如果您不想保留副本,请不要传递扩展参数。
答案 7 :(得分:7)
你可以使用vi
vi -c '%s/foo/bar/g' my.txt -c 'wq'
答案 8 :(得分:3)
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt
应保留所有硬链接,因为输出会被反向覆盖原始文件的内容,并且不需要特殊版本的sed。
答案 9 :(得分:3)
您还可以使用重定向运算符<>
打开要读写的文件:
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 Reference Manual → 3.6.10 Opening File Descriptors for Reading and Writing:
重定向运算符
[n]<>word
导致打开名称为word扩展名的文件 读取和写入文件描述符n或文件描述符0 如果没有指定n。如果该文件不存在,则会创建该文件。
答案 10 :(得分:1)
您没有指定正在使用的shell,但是使用zsh,您可以使用=( )
构造来实现此目的。有点像:
cp =(sed ... file; sync) file
=( )
与>( )
类似,但会创建一个临时文件,该文件会在cp
终止时自动删除。
答案 11 :(得分:0)
$ printf ',s/false/true/g\nw\n' | ed {YourFileHere}
快乐编辑到位。 添加了&#39; \ nw \ n&#39;写文件。抱歉延迟回答请求。
答案 12 :(得分:-1)
非常好的例子。我有挑战来编辑许多文件,-i选项似乎是在find命令中使用它的唯一合理的解决方案。这里的脚本在每个文件的第一行前添加“version:”:
find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;