执行命令的顺序和重定向

执行命令的顺序和重定向

对于我正在制作的 bash 脚本,我需要删除目录中除最新的 2 个文件之外的所有文件。

我决定使用ls -tUr > somefile.txt然后尾随最新的 2 个,将它们移到其他地方,rm *然后将它们移回来。

由于某种原因,somefile.txt实际上显示了(在其余文件中)somefile.txt其中使用命令搞砸了tail

所以我的问题是,逻辑上ls会返回当前文件夹/文件,然后被重定向到somefile.txt,但显然这不会发生,因为在运行somefile.txt之前必须存在;ls为什么是这样?

答案1

这回答了“为什么会发生这种情况?”的问题。

是的,实际上会在运行somefile.txt之前创建。ls

$ utility >file

首先发生的事情是 shell 注意到重定向,创建file(或截断它,如果它已经存在),然后它执行utility时其标准输出流进入file.

该实用程序通常不知道或不关心其标准输出的去向(有些实用程序,例如ls,会检查它是否是 TTY 并相应地更改其行为),因此它是否写入常规输出并不重要文件、管道、设备文件或套接字。这当然不关心创造这个文件。因此,shell 的工作是在进程启动之前确保管道就位,其中包括创建或截断file上例中指定的文件。

有关删除除最新文件之外的所有文件的问题的答案,请参阅问题“删除最旧的文件

答案2

虽然 Kusalananda 已经回答了您关于为什么somefile.txt出现在 的输出中的问题ls,但我将尝试解决有关如何删除除最近的两个之外的所有内容的问题已创建文件作为链接的问题最近处理修改的文件代替。

首先,您不必将输出写入文件中。命令可以直接相互交互,这就是管道的用途。

在这里,你可以这样做:

ls -tU | tail -n +3 | xargs echo rm -f -- # echo for dry-run

但这在一般情况下是有缺陷的,因为tail适用于行和xargs适用于(可能引用的)单词,并且文件名不能保证是其中任何一个。它们甚至不能保证是有效的文本。仅当文件名均不包含空格、换行符、引号、反斜杠或不形成有效字符的字节序列时,它才能正常工作。

如果系统是 FreeBSD(正如您的使用所-U建议的那样),您可以使用json可可靠解析的输出格式,例如:

ls --libxo=json -Ut |
  perl -MJSON::PP -l0 -0777 -ne '
    @files = map {$_->{name}} @{
      decode_json($_)->{"file-information"}->{directory}->[0]->{entry}
    };
    print for @files[2..$#files]' | xargs -0 echo rm -f --

相关内容