> For the complete documentation index, see [llms.txt](https://huataihuang.gitbook.io/cloud-atlas-draft/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://huataihuang.gitbook.io/cloud-atlas-draft/develop/shell/sed_awk/prevent_sed_-i_from_destroying_symlinks.md).

# 如何避免sed -i破坏文件的软链接

在排查 [systemd管理rc.local启动](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/os/linux/redhat/system_administration/systemd/rc_local/README.md) 问题时，发现每次安装rpm包的时候，原本系统中`/etc/rc.d/rc.local`的软链接文件`/etc/rc.local`被错误替换成了一个实体文件。

> 以下案例假设安装包名`example-rpm-package`，该rpm包包含了修订`rc.local`的操作。

## 排查过程

删除掉 `example-rpm-package` 可以看到`/etc/rc.local`被恢复成和`/etc/rc.d/rc.local`相同的旧版本。但是，请注意，这两个文件是完全独立的，并没有软链接关系！！！

```
sudo rpm -e example-rpm-package-1.1-release90.el7.x86_64
```

```
$ls -lh /etc/rc.local
-rwxr-xr-x 1 root root 786 Sep  4 19:37 /etc/rc.local

$md5sum /etc/rc.local
7970f518f50260f6f0421d83c45311d0  /etc/rc.local

$ls -lh /etc/rc.d/rc.local
-rwxr-xr-x 1 root root 786 Aug 29 14:51 /etc/rc.d/rc.local

$md5sum /etc/rc.d/rc.local
7970f518f50260f6f0421d83c45311d0  /etc/rc.d/rc.local
```

我们现在来恢复`/etc/rc.local`到`/etc/rc.d/rc.local`的软链接，然后看再次安装`example-rpm-package`包是否会破坏这个软链接

```
$sudo rm -f /etc/rc.local

$cd /etc/

$sudo ln -s rc.d/rc.local .

$ls -lh /etc/rc.local
lrwxrwxrwx 1 root root 13 Sep  4 19:42 /etc/rc.local -> rc.d/rc.local
```

重新安装一次相同版本的 example-rpm-package-1.1-release90.el7.x86\_64.rpm

```
sudo rpm -ivh example-rpm-package-1.1-release90.el7.x86_64.rpm
```

安装完成后检查可以看到`/etc/rc.local`被替换成实际文件，而不是软链接。而且可以看到rpm包修改的内容是作用于`/etc/rc.local`上，而不是正确的目标`/etc/rc.d/rc.local`

```
$ls -lh /etc/rc.local
-rwxr-xr-x 1 root root 863 Sep  5 00:03 /etc/rc.local
```

## `sed -i`默认不检查软链接！！！

原因是什么呢？检查这个rpm包的spec文件可以看到：

```
%post
...
#add turbo to rc.local
sed -i /myscript/d /etc/rc.local
echo "sh /usr/local/bin/myscript.sh" >> /etc/rc.local
```

在这个spec文件中，其他修改`rc.local`的sed命令都是直接修改`/etc/rc.d/rc.local`，但是上述`sed`指令错误修改软链接文件导致了`/etc/rc.local`到`/etc/rc.d/rc.local`的软链接被替换成实体文件：

* `sed`的`-i / --in-place`参数可以直接修改文件。但是，默认情况下，`sed`在读取文件之前不会检查文件是否是软链接，所以`sed`转换之后覆盖原文件（`sed`相当于将原文件通过流方式过滤改成，然后通过管道生成临时文件，然后删除掉原文件，再将临时文件重命名成原文件）。这就导致了如果原文件是一个软链接，就会在修改后转变成实体文件。
* GNU `sed` 提供了一个`--follow-symlinks`参数，可以检测修改的是软链接，而实现对软链接指向的实体文件的修改，避免破坏软链接。案例如下：

```
$ echo "cat" > pet
$ ln --symbolic pet pet_link
$ sed --in-place --follow-symlinks 's/cat/dog/' pet_link
$ cat pet
dog
```

## 参考

* [How do I prevent sed -i from destroying symlinks?](https://unix.stackexchange.com/questions/192012/how-do-i-prevent-sed-i-from-destroying-symlinks)
* [How to prevent sed -i command overwriting my symlinks on Linux or Unix](https://www.cyberciti.biz/faq/howto-prevent-sed-i-from-destroying-symlinks-on-linux-unix/)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://huataihuang.gitbook.io/cloud-atlas-draft/develop/shell/sed_awk/prevent_sed_-i_from_destroying_symlinks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
