我的项目需要替换文件中的一些现有文本,例如foo
与其他一些文字,如fooofoo
:
abc.txt
name
foo
foo1
所以我尝试:
sed -i "s/foo/fooofoo/g" abc.txt
但是我收到这个错误:
sed:非法选项--
i
我在手册中发现我必须使用:
sed -i\ "s/foo/fooofoo/g" abc.txt
然而这也不起作用。
我在perl
和中找到了替代方案awk
,但如果能在 Solaris 中找到解决方案,我sed
将不胜感激。
我正在使用这个版本的 bash:
GNU bash,版本 3.2.57(1)-release (sparc-sun-solaris2.10)
答案1
使用ed
。它适用于大多数平台,并且可以就地编辑您的文件。
由于sed
基于ed
替换模式的语法类似:
ed -s infile <<\IN
,s/old/new/g
w
q
IN
答案2
如果无法安装 GNU sed,请使用:
sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt
这使用重定向将 sed 的输出发送到临时文件。如果 sed 成功完成,则会覆盖abc.txt
临时文件。
从GNU sed的源代码可以看出,这正是sed -i
所做的。因此,这与sed -i
.
如果有可能abc.tmp
已经存在,那么您可能需要使用mktemp
或类似的实用程序来为临时文件生成唯一的名称。
答案3
如果你想要 的等价物sed -i.bak
,那非常简单。
考虑 GNU sed 的这个脚本:
#!/bin/sh
# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"
# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'
##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########
# Prove that it worked
ls "$dir"
cat "$dir/foo"
我们可以简单地将标记线替换为
cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"
这会将现有文件移动为备份,并写入新文件。
如果我们想要相当于
sed -i -e "$script" "$dir" # no backup
那么就稍微复杂一些。我们可以打开文件作为标准输入读取,然后取消链接它,然后指示 sed 的输出替换它:
( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )
我们在子 shell 中执行此操作,以便我们的原始标准输入在此之后仍然可用。可以在没有子外壳的情况下切换输入并切换回来,但这种方式对我来说似乎更清晰。
请注意,我们首先要小心复制,而不是创建一个新foo
文件 - 如果该文件有多个名称(即具有硬链接)并且您希望确保不会破坏链接,这一点很重要。
答案4
使用sed
与否可见的临时文件:
您可以避免创建单独的可见的“临时文件”:
exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-
解释
类 Unix 系统实际上不会从磁盘中删除文件的内容,直到文件被删除为止。两个都在文件系统中取消链接,和不在任何进程中打开。因此,您可以exec 3<
在 shell 中打开文件以读取文件描述符 3 rm
(该文件将其与文件系统取消链接),然后sed
使用文件描述符 3 作为其输入进行调用。
请注意,这是非常与此不同:
# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt
不同之处在于,当您在一个命令中执行此操作时,外壳程序只会打开同一个文件进行读取和写入,并带有截断文件的选项 - 因为它仍然是同一个文件,所以您会丢失内容。但是,如果您打开它进行读取,然后rm
打开它,然后打开相同的路径名进行写入,您实际上是在相同的路径名下创建一个新文件(但在新的索引节点和磁盘位置,因为原始文件仍然打开):所以内容仍然可用。
然后,完成后,您可以关闭之前打开的文件描述符(这就是exec 3<&-
特殊语法的作用),这会释放原始文件,以便操作系统可以删除(标记为未使用)其磁盘空间。
注意事项
关于此解决方案,需要记住以下几点:
您只能“浏览”一次内容 - 没有便携的shell 在文件描述符中“寻找”的方式 - 因此一旦程序读取了某些内容,其他程序将只能看到文件的其余部分。并将
sed
读取整个文件。如果您的 shell/script/sed 在完成之前被杀死,则原始文件丢失的可能性很小。