我的问题类似于如何防止 sed -i 破坏符号链接?,但涉及硬链接。
使用sed -i
来处理文件会破坏该文件具有的所有硬链接,因为 sed 通过写入临时文件然后移动它来工作。该--follow-symlinks
参数在硬链接的情况下没有帮助。
除了使用相当丑陋的方法之外,还有其他选择吗:
sed 's/cat/dog/' pet_link > pet_link
答案1
对于sed 's/cat/dog/'
任何不改变文件大小的其他替换,使用任何类似 Bourne 的 shell,您可以执行以下操作:
sed 's/cat/dog/' < file 1<> file
鲜为人知但超过 35 岁的人标准 <>
操作符是以读+写模式打开文件没有截断。基本上,这里将sed
其输出写入其输入。确保输出不会覆盖文件中sed
尚未读取的部分非常重要。
对于导致文件大小减小的替换,使用ksh93
:
sed 's/hippopotamus/ant/' < file 1<>; file
<>;
,ksh93
扩展名与 相同,<>
只是如果重定向的命令成功,文件将在命令完成的位置被截断。
或者使用 perl:
perl -pe 's/hippopotamus/ant/;
END{truncate STDOUT, tell STDOUT}' < file 1<> file
对于其他任何事情,只需使用标准形式:
cp -i file file.back &&
sed 's/dog/horse/g' < file.back > file # && rm -f file.back
1 尽管 Bourne shell 和 Korn shell 早期版本中的最初实现实际上已被破坏,但在 80 年代末已得到修复。 Almquist shell 最初并不支持它。
答案2
请注意,这sed
是一个S特雷姆急诊科它,不是一个文件编辑器,因此人们倾向于滥用它来尝试编辑文件。基本上-i
选项是非标准 FreeBSD 扩展(可能在其他操作系统上不可用),其次它不编辑文件 - 它会创建一个副本并用副本替换原始文件。Bash常见问题解答
另一种方法是使用ed
或ex
具有类似语法的命令(Vim 的一部分),例如
ex +%s/cat/dog/e -scwq pet_link
或者按照@通配符推荐:
printf '%s\n' '%s/cat/dog/' x | ex pet_link
对于多个文件,您可以使用:
ex "+bufdo! %s/foo/bar/ge" -scxa **/*.lnk
如果你的 shell 支持一个新的通配选项(通过:启用shopt -s globstar
),**
在这种情况下使用将递归地工作。
for f in *.txt; do printf '%s\n' '%s/cat/dog/g' x | ex "$f"; done
或者:
find . -type f -exec sh -c 'for f; do printf "%s\n" "%s/cat/dog/g" x | ex "$f"; done' sh {} +
有关的:
答案3
一点儿ed
:
$ ed pet_link <<END_OF_ED
g/cat/s//dog/
w
END_OF_ED
这不会破坏硬链接。
答案4
我发现这效果很好(保留符号链接和硬链接):
sed 's/cat/dog/' pet_link > pet_link.tmp
cat pet_link.tmp > pet_link
rm pet_link.tmp