将文件列表筛选为存在的文件



如何将文件列表过滤为存在的文件?

例如

echo 'a.txt
does/not.exist
b.txt' | <???>

会打印

a.txt
b.txt 

您可以ls -d文件并查看哪些文件获得一些输出。由于字符串中有它们,因此只需通过管道传输列表并使用xargs即可ls它们。

要隐藏错误,请将这些错误重定向到 /dev/null 。总之,xargs ls -d 2>/dev/null做到了:

$ echo 'a.txt
b.txt
other' | xargs ls -d 2>/dev/null
a.txt
b.txt

如您所见,xargs ls -d执行ls -d给出的所有参数。 2>/dev/null摆脱了标准消息。

如果您有 GNU xargs,请使用 -d 'n' 来确保正确处理带有嵌入空格的文件名(包括目录),方法是将输入拆分为行而不是行内空格。

echo 'a.txt
does/not.exist
b.txt' | xargs -d 'n' ls -1df 2>/dev/null

注意:

  • ls 命令为每个不存在的输入路径发出错误,2>/dev/null忽略该错误,同时按原样回显现有路径。

  • 选项 -1 将每个路径打印在自己的行上,-d防止递归到目录中,-f防止对输入路径进行排序(如果确实排序,请省略f)。

<小时 />

macOS/BSD上,xargs不支持-d,这需要使用trxargs-0选项通过NUL分隔的输入进行解决方法:

echo 'a.txt
does/not.exist
b.txt' | tr 'n' '' | xargs -0 ls -1df 2>/dev/null

作为单行,纯粹的速度猛击(从 mklement0 的答案改进,如果我有代表,我会发表评论):

{ ls; echo does/not.exist; } | while IFS= read -r f; do [[ -f "$f" ]] && echo "$f"; done

我想出的第一件事,在 while read 循环中使用 stats 的退出代码:

<input> | while IFS= read -r f; do stat "$f" &>/dev/null && echo "$f"; done

请注意,此解决方案很慢,因为它在 shell 代码中循环,并调用外部实用程序(创建子进程,stat )在每次迭代中。

我会使用 bash 的 if 来检查文件。它最终有点不那么紧凑,但我认为它更清晰,并且更容易对结果中的每个找到的文件做一些事情。

它与带空格的文件名兼容。

echo 'a.txt
does/not.exist
b.txt' | while read filename
do
  if [[ -f "$filename" ]]
  then
    echo $filename # Or do something else with the files here
  fi
done
<</div> div class="one_answers">

可以将多个文件传递给stat,如果文件不存在,则只会向STDERR打印一条消息。所以你可以这样做:

<input> | xargs stat --printf '%nn' 2> /dev/null

或者,如果您使用的是以 null 结尾的路径(我推荐并且无法使用 ls):

<input> | xargs -0 stat --printf '%n' 2> /dev/null

相关内容

  • 没有找到相关文章

最新更新