使用sed与否可见的临时文件:

使用sed与否可见的临时文件:

我的项目需要替换文件中的一些现有文本,例如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<&-特殊语法的作用),这会释放原始文件,以便操作系统可以删除(标记为未使用)其磁盘空间。

注意事项

关于此解决方案,需要记住以下几点:

  1. 您只能“浏览”一次内容 - 没有便携的shell 在文件描述符中“寻找”的方式 - 因此一旦程序读取了某些内容,其他程序将只能看到文件的其余部分。并将sed读取整个文件。

  2. 如果您的 shell/script/sed 在完成之前被杀死,则原始文件丢失的可能性很小。

相关内容