qy711 发表于 2023-10-8 16:49

为什么 cat < w1 > w1会清空 W1


在Linux环境下,w1内有内容,当输入cat < w1 > w1 时,w1内容会清空,请问是什么原理,哪位大牛帮解释下???

hrh123 发表于 2023-10-8 17:33

本帖最后由 hrh123 于 2023-10-8 17:58 编辑

**没记错的话**好像是先处理`>`的

***

***编辑***

貌似记错了,好像是同时运行还是咋的,机制我也不知道,man page上也没翻到,等大佬吧

周易 发表于 2023-10-8 22:52

本帖最后由 周易 于 2023-10-8 22:53 编辑

以下以`Bash`为例,我们假定文件名为`w1`。需要注意的是,不同Shell可能有不同的实现方式。

> Redirections are processed in the order they appear, from left to right.

因此不是优先级问题。

我们首先明确一点:重定向是怎么实现的。

实现输入重定向(`STDIN_FILENO = 0`)的伪代码如下。

```c
fd = openat(AT_FDCWD, "w1", O_RDONLY);
dup2(fd, STDIN_FILENO);
close(fd);
```

实现输出重定向(`STDOUT_FILENO = 1`)的伪代码如下。

```c
fd = openat(AT_FDCWD, "w1", O_WRONLY | O_CREAT | O_TRUNC, 0666);
dup2(fd, STDOUT_FILENO);
close(fd);
```

这些都是在执行`cat`之前**依次**发生的。

对于以下两种方式:

- cat < w1 > w1
- cat > w1 < w1

区别只在于执行伪代码两者的顺序不同。

不难发现,如果指定了输出重定向,则在打开文件过程中`w1`的内容将会被清空。

> **`O_TRUNC`**
>
> If the file already exists and is a regular file and the access mode allows writing (i.e., is `O_RDWR` or `O_WRONLY`) it will be truncated to length 0.

Seven_2017 发表于 2023-10-8 23:07

有点厉害哦,我只知道重定向空到文件w1所以清空了

爱飞的猫 发表于 2023-10-8 23:11

因为是同时打开的。一个是打开只读 `< w1`,一个是打开时就清空文件 `> w1`。

如果你真的需要达到你想要的效果,你应当使用 `sponge` 指令:

```bash
cat w1 | sponge w1
```

注意他也没用 `>` 符号(如果真用了就直接清空了)。原理则是将管道传输进来的数据全部放到内存,然后等 `stdin` 结束写入后再打开文件写出。

qy711 发表于 2023-10-8 23:30

爱飞的猫 发表于 2023-10-8 23:11
因为是同时打开的。一个是打开只读 `< w1`,一个是打开时就清空文件 `> w1`。

如果你真的需要达到你 ...

请问"一个是打开时就清空文件 `> w1`" 这打开的是W1 还是不存在的空值?

爱飞的猫 发表于 2023-10-8 23:33

qy711 发表于 2023-10-8 23:30
请问"一个是打开时就清空文件 `> w1`" 这打开的是W1 还是不存在的空值?

w1 不是你 1L 描述里用的文件名吗…

另外建议你看 @周易 在上面的答案,是根据源码分析的:

https://www.52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=1841941&pid=48188419

hrh123 发表于 2023-10-9 20:42

爱飞的猫 发表于 2023-10-8 23:33
w1 不是你 1L 描述里用的文件名吗…

另外建议你看 @周易 在上面的答案,是根据源码分析的:


我想知道这个<>是bash内建的还是cat自带的{:301_1009:}

爱飞的猫 发表于 2023-10-9 20:53

hrh123 发表于 2023-10-9 20:42
我想知道这个是bash内建的还是cat自带的

Shell 实现的。如果你使用的是 Bash 作为 Shell 解释器,那就是 Bash。

hrh123 发表于 2023-10-14 20:23

爱飞的猫 发表于 2023-10-9 20:53
Shell 实现的。如果你使用的是 Bash 作为 Shell 解释器,那就是 Bash。

所以问题就在于shell在执行cat读取数据前先处理了重定向,打开并O_TRUNC了文件,我的理解没问题吧{:301_1009:}
页: [1] 2
查看完整版本: 为什么 cat < w1 > w1会清空 W1