当我将 ls 的输出重定向到一个文件时,文件名包含在该文件中。我怎样才能避免这种情况?

Ste*_* Lu 7 command-line ls shell io-redirection

观察:

$ ls
$ ls > list
$ cat list
list
Run Code Online (Sandbox Code Playgroud)

这似乎表明ls执行时重定向到文件list已经开始并且list文件已经创建。无论如何,这是一个足够好的解释,但问题是:我怎样才能防止这种情况发生?我期望发生的是ls将执行并将其输出转储到其中list,这就是我想要的。

Ste*_*ris 15

正如您所注意到的,文件是在ls运行之前创建的。这是由于外壳如何处理其操作顺序。为了做到

ls > file
Run Code Online (Sandbox Code Playgroud)

shell 需要创建 file然后设置 stdout 指向它,最后运行ls程序。

所以你有一些选择。

  1. 在另一个目录(例如/tmp)中创建文件,然后将mv其创建到最终目录
  2. 将其创建为隐藏文件 ( .file) 并重命名
  3. 用于grep从输出中删除文件
  4. 欺骗 :-)

作弊会是这样的

x=$(ls) ; printf "%s\n" "$x" > file
Run Code Online (Sandbox Code Playgroud)

这会导致 的输出ls保存在一个变量中,然后我们将其写出。


Fox*_*Fox 10

输出文件在ls开始之前由 shell 创建。您可以使用tee以下方法解决此问题:

ls | tee list
Run Code Online (Sandbox Code Playgroud)

要彻底击败任何比赛条件,总有

ls | grep -vx 'list' > list
Run Code Online (Sandbox Code Playgroud)

或者,如果您喜欢,也可以tee显示结果:

ls | grep -vx 'list' | tee list
Run Code Online (Sandbox Code Playgroud)

然而,正如评论中指出的那样,当文件名包含奇怪的字符时,这样的事情经常会中断。Unix 文件名通常可以包含除NULand之外的任何字符/,因此解析 的输出ls非常困难:

  • 如果文件名以一个或多个\n.
  • grep当搜索词位于 之间时,过滤失败\n
  • 您可以使用NUL而不是\n使用来分隔文件名find,但可能很难将其转换为类似于传统排序的、以换行符分隔的ls.
  • 如果已存在,则从列表中删除输出文件名可能不正确。

因此,唯一真正有效的方法是在其他地方创建输出文件,然后将其移动到位。如果您永远不会使用ls -a,那么这有效:

ls > .list && mv .list list
Run Code Online (Sandbox Code Playgroud)

如果您可能正在使用ls -a,则.list可能会出现在您的输出中,但不再存在于目录中。那么你会使用一个不同的目录,比如/tmp存储中间结果。当然,如果你总是使用/tmp你会在那里遇到麻烦,所以你可以写一个脚本:

#!/bin/sh
OUTDIR='/tmp'
if [ "${PWD}" = '/tmp' ]; then
  OUTDIR="${HOME}"
fi
ls > "${OUTDIR}/list" && mv "${OUTDIR}/list" list
Run Code Online (Sandbox Code Playgroud)

不过,这对于任务来说似乎过于复杂。

但问题的全部原因是 shell 在命令开始之前创建了输出文件。我们可以考虑到这一点,让 shell 为我们列出文件。那我们根本就不需要ls

printf '%s\n' * > list
Run Code Online (Sandbox Code Playgroud)

这将一直有效,直到目录中有太多文件无法放入参数列表。


Sté*_*las 5

您可以使用moreutils sponge

ls | sponge list
Run Code Online (Sandbox Code Playgroud)

或者与zsh

cp =(ls) list
Run Code Online (Sandbox Code Playgroud)

使用 GNU ls

ls -I list > list
Run Code Online (Sandbox Code Playgroud)

(尽管如果之前调用过一个文件list,则意味着它不会被列出)。

由于ls无论如何输出都是排序的,您也可以使用(假设您的文件名不包含换行符):

ls | sort -o list
Run Code Online (Sandbox Code Playgroud)

或者为了避免双重排序,如果您ls支持-Unsorted U(注意某些ls实现有 a-U为其他东西):

ls -U | sort -o list
Run Code Online (Sandbox Code Playgroud)