将一个文件重定向到另一个文件是否是 UUOC(对 cat 的无用使用)?

Wil*_*ard 37 io-redirection file-copy files cat

如果我想让 的内容file2匹配 的内容file1,我显然可以直接运行cp file1 file2.

但是,如果我想保留一切有关file2 除了内容所有者,权限,扩展属性,ACL的,硬链接,等等等等,那么我就不会想运行cp。*在这种情况下,我只是想在扑通file1into 的内容file2

似乎以下内容可以做到:

< file1 > file2
Run Code Online (Sandbox Code Playgroud)

但它不起作用。 file2被截断为空且不写入。然而,

cat < file1 > file2
Run Code Online (Sandbox Code Playgroud)

确实有效。

我很惊讶第一个版本不起作用。

第二个版本是UUOC吗?有没有办法在不调用命令的情况下仅通过使用重定向来做到这一点?

注意:我知道 UUOC 与其说是真正的反模式,不如说是一种迂腐的观点。

*正如tniles09 发现的那样,实际上在这种情况下cp 起作用。

PSk*_*cik 59

cat < file1 > file2不是 UUOC。经典地,<>在系统级别执行与文件描述符重复相对应的重定向。文件描述符重复本身不会做任何事情(好吧,>重定向以O_TRUNC开头,所以准确地说,输出重定向确实会截断输出文件)。不要让< >符号混淆你。重定向不会移动数据——它们将文件描述符分配给其他文件描述符。

在这种情况下,您打开file1该文件描述符并将其分配给文件描述符0<file1== 0<file1),file2并将该文件描述符分配给文件描述符1>file2== 1>file2)。

现在您有两个文件描述符,您需要一个进程来在两者之间挖掘数据——这就是cat它的目的。

  • 也许只有我一个人,但这个答案中我最喜欢的部分是你对“铲子”这个词的使用。:) 很清楚,谢谢。 (11认同)

tni*_*les 17

事实并非如此,因为正如其他人所指出的那样,所讨论的行为是依赖于 shell 的。正如您(OP)所指出的,这有点迂腐,甚至可能是幽默?,话题之类的。

但是,在 GNU 系统上,您的初始前提有另一个可用的解决方案:cp --no-preserve=all file1 file2. 试试这个,我认为它会满足您描述的情况(例如,修改内容file2而不修改其属性)。

示例

$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 16 Dec 16 12:21 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Lookout, world!
    Hello, world!
$ cp --no-preserve=all fred fezzik 
$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 14 Dec 16 12:22 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Hello, world!
    Hello, world!
Run Code Online (Sandbox Code Playgroud)

更新 实际上,我只是注意到我的系统cp本身似乎保留属性,除非指定-a-p指定。我正在使用 bash shell 和 GNU coreutils。我猜你每天都会学到一些新东西......


测试结果(通过通配符)包括硬链接和不同的权限:

$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 file2
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the original contents of file2
$ cp file1 file2
$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 file2
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the contents of file1
$ 
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 13

zsh, 工作的 shell 中< file1 > file2,shell 确实调用了cat.

对于仅包含重定向且不包含命令或赋值的命令行,zsh调用$NULLCMDcat默认情况下)除非唯一的重定向是<在这种情况下$READNULLCMDpager默认情况下)被调用。(除非zsh是 inshcshemulation,在这种情况下它的行为就像它模拟的 shell)。

所以:

< file1 > file2
Run Code Online (Sandbox Code Playgroud)

实际上是一样的

cat < file1 > file2
Run Code Online (Sandbox Code Playgroud)

< file1
Run Code Online (Sandbox Code Playgroud)

是相同的

pager < file1
Run Code Online (Sandbox Code Playgroud)


Kaz*_*Kaz 8

< from > to
Run Code Online (Sandbox Code Playgroud)

不起作用,因为那里没有命令;没有过程。shell 打开/创建文件并安排重定向(意味着引用这些文件的文件描述符被植入 0 和 1:标准输入和标准输出)。但是没有什么可以执行循环从标准输入读取并写入标准输出。

zsh通过在这种“空命令”情况下替换用户可配置的命令来完成这项工作。该命令在命令行中不可见,但它仍然存在。为它创建了一个流程,它的工作方式相同。NULLCMDcat在默认情况下,所以< from > to实际上意味着 cat < from > tozsh,除非NULLCMD设置为别的东西; 这是一个“隐式猫”命令。

cat用作中介从文件中读取数据并将数据提供给另一个进程时,就会发生“无用的使用 cat” ,该进程的文件描述符可以连接到原始文件。

如果cat可以从情况中移除,使得剩余的命令仍然可以执行相同的任务,则没有用。如果它是不可拆卸的,那么它不是没用的。

# useless, removable:
$ cat archive.tar | tar tf -    #  -->  tar tf archive.tar

# not removable (in POSIX shell):
$ cat > file
abc
[Ctrl-D]

# likewise:
STRING=$(cat file)
Run Code Online (Sandbox Code Playgroud)

cat替换的A不是一回事。例如,cat > file我们可以用它vi file来创建文件。这不算是删除cat,而使用剩下的任何东西来完成相同的任务。

如果cat是管道中唯一的命令,那么当然不能删除;剩下的任何东西都没有重新排列将做同样的工作。

一些 shell 脚本编写者使用cat它是因为他们认为这可以让他们将输入操作数移动到更靠近命令行左侧的位置。但是,重定向可以在命令行中的任何位置:

# If you're so inclined:
# move source archive operand to the left without cat:
$ < archive.tar tar xf - > listing
Run Code Online (Sandbox Code Playgroud)