Bash 将文件列表筛选到存在的文件
如何将文件列表筛选到存在的文件 比如说,Bash 将文件列表筛选到存在的文件,bash,file,Bash,File,如何将文件列表筛选到存在的文件 比如说, echo 'a.txt does/not.exist b.txt' | <???> 您可以ls-d文件,并查看哪些文件得到一些输出。由于这些都在一个字符串中,只需通过管道传输列表并使用xargs即可ls它们 要隐藏错误,请将这些错误重定向到/dev/null。总之,xargs ls-d2>/dev/null使其: $ echo 'a.txt b.txt other' | xargs ls -d 2>/dev/null a.txt b.
echo 'a.txt
does/not.exist
b.txt' | <???>
您可以
ls-d
文件,并查看哪些文件得到一些输出。由于这些都在一个字符串中,只需通过管道传输列表并使用xargs
即可ls
它们
要隐藏错误,请将这些错误重定向到/dev/null
。总之,xargs ls-d2>/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
删除了stderr消息。我想到的第一件事是,在while read循环中使用stats
的退出代码:
<input> | while IFS= read -r f; do stat "$f" &>/dev/null && echo "$f"; done
|而IFS=read-rf;统计“$f”&>/dev/null&&echo“$f”;完成
请注意,此解决方案速度较慢,因为它在shell代码中循环,并调用
外部实用程序(在每次迭代中创建一个子进程,stat
。如果您有GNUxargs
,请使用-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
,这需要使用tr
和xargs
的-0
选项通过NUL分隔输入解决:
echo 'a.txt
does/not.exist
b.txt' | tr '\n' '\0' | xargs -0 ls -1df 2>/dev/null
我会使用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
作为一个单行程序,纯bash的速度(从mklement0的答案改进而来,如果我有代表的话,我会评论):
... 关于解析
ls
输出的常见警告;例如,如果其中一个参数是一个目录,您将得到目录的内容,而不是它的名称。好的一个,可能是ls-d
最好。在Ubuntu上,echo”“|(xargs ls-d 2>/dev/null)
在输出中显示为
,这似乎是因为ls-d
导致
。这似乎可以通过无条件地预先添加一个换行来纠正:echo”“|(echo“\n”和&cat)|(xargs ls-d2>/dev/null)
。把第一个echo想象成可能导致一个空行的命令;可能值得添加-1
,以确保逐行输出,并添加-f
,以防止输入路径被排序(尽管您实际上可能更喜欢这样)。另外,请注意,带有嵌入空格的文件名将无法正确处理。如果将stat“$f”&&
替换为if![[-e“$f”|-h“$f”]];然后
,这就成了C级代码上非常薄的包装。实际上,我希望它会非常快。不错,虽然而IFS=read-r filename
会使它更健壮(正确处理带有空格的文件名,不会意外解释转义序列)。不错,尽管你可能是说。至于速度优势:对于少量输入线,这可能比基于外部实用程序的解决方案性能更好,但对于大量输入线,后者可能更快。权衡是创建子进程的成本与缓慢的shell代码循环。
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
{ ls; echo does/not.exist; } | while IFS= read -r f; do [[ -f "$f" ]] && echo "$f"; done