cat和'>'之间的差异将文件归零


23

这两个命令对文件归零的方式是否有所不同?后者是做前者的较短方法吗?幕后发生了什么?

$ cat /dev/null > file.txt

$ > file.txt 

-rw-r--r--  1 user  wheel  0 May 18 10:33 file.txt

Answers:


28

cat /dev/null > file.txt无用的

基本上cat /dev/null只是导致cat什么都不输出。是的,它可以工作,但是许多人对此并不满意,因为它会导致调用不必要的外部过程。
这是很常见的事情之一,因为它很常见。

> file.txt在大多数shell上都可以使用just ,但是它并不是完全可移植的。如果要完全便携,可以使用以下替代方法:

true > file.txt
: > file.txt

两个:true输出没有数据,并且是shell内建(而cat是外部实用程序),因此它们更轻,更“适当的”。

 

更新:

正如tylerl在他的评论中提到的那样,还有>| file.txt语法。

大多数shell都有一个设置,可以防止它们通过截断现有文件>。您必须>|改为使用。当您确实要附加时,这是为了防止人为错误>>。您可以使用打开行为set -C

因此,我认为截断文件的最简单,最适当和可移植的方法是:

:>| file.txt

2
Colon命令在POSIX中定义。这是一个空操作,用于扩展命令行参数。
kojiro 2014年

3
大声笑,“虐待猫”
KM。

2
:POSIX还要求@kojiro 也是内置的,实际上true,它不同于被认为是“特殊”内置的
jw013

2
不要忘记noclobber>| file是一个更明确的截断。
tylerl

1
No true不需要内置,传统上不是。:建在伯恩家族的所有贝壳中。:是每个POSIX的一个特殊内置函数(: > file例如,如果file无法打开以在POSIX Shell中进行写操作,则会退出该Shell ),但true不是。POSIX甚至提到它:可能比某些系统更有效true
斯特凡Chazelas

23

在可移植性方面:

                      Bourne POSIX  zsh    csh/tcsh  rc/es  fish
> file                Y      Y      N(1)   N(1)      N      N
: > file              N/Y(2) Y(3)   Y      Y(4)      N(5)   N(5)
true > file           Y(5)   Y      Y      Y(5)      Y(5)   Y(5)
cat /dev/null > file  Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
eval > file           Y(3,8) Y(3)   Y      Y(6)      Y      Y
cp /dev/null file (7) Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
printf '' > file      Y(5)   Y      Y      Y(5)      Y(5)   Y

笔记:

  1. 除in shksh仿真外,对于zsh中不带命令的重定向,假定使用默认命令(cat否则,仅使用stdin重定向的传呼机),可以使用NULLCMD和READNULLCMD变量进行调整。灵感来自的类似功能(t)csh
  2. 最初:在UnixV7中不执行重定向,因为:注释领导者和null命令之间进行了中途解释。后来,它们像所有内建程序一样,如果重定向失败,则退出外壳。
  3. :eval是特殊的内置插件,如果重定向失败,则会退出外壳程序(bash仅在POSIX模式下会这样做)。
  4. 有趣的是 (t)csh,它定义了一个null标签(用于goto),因此goto ''将在那里分支。如果重定向失败,则退出外壳。
  5. 除非/如果对应的命令是在可用的$PATH:一般不; truecatcpprintf通常是(POSIX要求它们))。
  6. 如果重定向失败,则退出外壳。
  7. file但是,如果是到不存在文件的符号链接,则某些cp实现(例如GNU的实现)将拒绝创建该文件。
  8. 尽管 Bourne Shell的初始版本不支持重定向内置函数

就易读性而言:

(本节是主观的)

  • > file。这>看起来太像一个提示或注释。另外,我在阅读时会问的问题(大多数shell都会抱怨这一点)您要重定向的输出什么?
  • : > file:被称为no-op命令。因此,立即读取为生成一个空文件。但是,这里再次:很容易错过和/或将其视为提示。
  • true > file布尔与重定向或文件内容有什么关系?这是什么意思是我读到的第一件事。
  • cat /dev/null > file串联/dev/nullfile cat而往往被视为命令转储文件的内容,仍然是有意义的:转储内容空文件到file,有点像一个令人费解的方式说cp /dev/null file,但还是可以理解的。
  • cp /dev/null file将空文件的内容复制到file。很有道理,尽管有人不知道cp默认情况下该怎么做可能会认为您正在尝试制作file一个null设备也是如此。
  • eval > fileeval '' > file。不执行任何操作并将其输出重定向到file。我感觉合理。奇怪的是,这不是一个常见的成语。
  • printf '' > file:显式不打印任何文件。对我来说最有意义的那个

在表现方面

不同之处在于我们是否使用内置的Shell。如果不是,则必须派生一个进程,并加载并执行命令。

eval保证可以在所有shell中构建。:内置在任何可用的地方(Bourne / csh喜欢)。true仅在类似Bourne的外壳中内置。

printf内置了大多数现代的Bourne式外壳和fish

cp并且cat通常不是内置的。

现在cp /dev/null file不调用shell重定向,因此类似:

find . -exec cp /dev/null {} \;

将会比:

find . -exec sh -c '> "$1"' sh {} \;

(尽管不一定比:

find . -exec sh -c 'for f do : > "$f"; done' sh {} +

)。

亲自

就个人而言,我使用的: > file是类似Bourne的贝壳,如今除了使用类似的Bourne以外的贝壳,什么也不要使用。


dd of=file count=0
kojiro 2014年

2
@kojiro,使用某些实现dd(至少像Solaris 10一样),将count=0被忽略。dd if=/dev/null of=file会更便携。无论如何,那都是独立于shell的。
斯特凡Chazelas

好的,但是值得一提的是cp /dev/null file,对吧?
kojiro 2014年

2
@kojiro cp /dev/null file是一个常见的成语。我仅限于这些,重点不是列出所有可能的方式。
斯特凡Chazelas

5

您可能要看一下truncate,它确实可以做到:截断文件。

例如:

truncate --size 0 file.txt

这可能比使用慢true > file.txt

但是,我的主要观点是:truncate用于截断文件,而使用>则具有截断文件的副作用。


2
当您想将文件截断为0以外的其他内容时,截断是很好的方法。也就是说,即使没有shell,这也是一个奇怪的陈述:您可以描述一个上下文,该上下文在哪里truncate可用,但是C库>unistdC库都不可用吗?
kojiro 2014年

并不是的。对于每种可用的脚本或编程语言,可能都有一个更优雅的解决方案。
Fabian

3
truncate是FreeBSD实用程序,相对来说最近(2008年)添加到了GNU coreutils中(尽管--sizeGNU长选项样式是GNU特定的),因此它在非GNU或FreeBSD系统中不可用,并且在较旧的GNU系统中不可用,我不会说它是便携式的。cp /dev/null file无需外壳重定向即可工作,并且更加便携。
斯特凡Chazelas

好的,我将删除该可移植性注释。尽管您对最近的定义似乎有所不同。
Fabian 2014年

2

答案取决于什么 file.txt以及如何写入!

我会举一个常见的用例:您的日志文件越来越多, file.txt,并希望对其进行轮换。

因此,例如,您将复制file.txtfile.txt.save,然后截断file.txt

在这种情况下,如果文件不是由another_process(例如:another_process可能是一个输出到该文件的程序,例如记录某些内容的程序),那么您的两个建议是等效的,并且都可以正常工作(但第二个建议是可取的)第一个“ cat / dev / null> file.txt”是Cat的无用用法,并且还会打开并读取/ dev / null)。

但是真正的麻烦是如果other_process仍然处于活动状态,并且仍然具有打开file.txt的句柄。

然后,根据other process文件的打开方式,出现两种主要情况:

  • 如果other_process以正常方式打开它,则该句柄仍将指向文件中的先前位置,例如,偏移量为1200个字节。因此,下一次写操作将从偏移量1200开始,因此,您将再次拥有1200bytes文件(+所写的other_process),其中包含1200个前导空字符!我想不是你想要的

  • 如果在“追加模式”下other_process打开file.txt,则每次写入时,指针都会主动寻找到文件末尾。因此,当您截断它时,它将“搜索”到字节0,并且不会有不良影响!这就是您想要的(...通常!)

请注意,这意味着在截断文件时,需要确保所有other_process仍在写入该位置的文件都已在“追加”模式下将其打开。否则,您需要停止这些操作other_process,然后重新启动它们,以便它们开始指向文件的开头而不是先前的位置。

参考:https : //stackoverflow.com/a/16720582/1841533进行了更简洁的解释,并在/programming//a/984761/1841533上介绍了正常模式和附加模式日志记录之间的区别的简短示例


2
这个答案实际上很少涉及或回答问题。a cat /dev/null > file和a 之间的区别> file是a cat /dev/null,对文件没有影响。
jw013

@ jw013:是的!但是我只是想利用这个问题的机会来重新陈述“您想要什么/不想要什么”信息,因为它不是很为人所知,并且可能会给试图轮换日志的人造成沉重打击(这是常见的情况,您想要截断文件)。
奥利维尔·杜拉克

1
有时间和地方放所有东西。您的信息在其他情况下可能很有用,但它不属于此处-您应该找到一个更合适的位置,因为没有人尝试轮换日志会在这个完全不相关的重定向问题中进行查找。在这里,您的答案等同于数字杂草,就像在玉米田中部其他有用的南瓜植物将被视为杂草一样。
jw013 2014年

1

我喜欢并经常使用它,因为它看起来更干净,而不像有人不小心按了回车键:

echo -n "" > file.txt

也应该是内置的吗?


3
将文件归零的方法有很多。我认为是KM。只想了解问题中显示的两种方法之间的区别。
DRS

6
许多echo实现不支持-n(并且将-n<SPC><NL>在此处输出。printf '' > file.txt会更加便携(至少在现代/ POSIX系统中))
StéphaneChazelas 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.