How do I filter a list of files to the ones that exist?
For example,
echo 'a.txt
does/not.exist
b.txt' | <???>
would print
a.txt
b.txt
You can ls -d
the files and see which ones get some output. Since you have those in a string, just pipe the list and use xargs
to be able to ls
them.
To hide errors, redirect those to /dev/null
. All together, xargs ls -d 2>/dev/null
makes it:
$ echo 'a.txt
b.txt
other' | xargs ls -d 2>/dev/null
a.txt
b.txt
As you see, xargs ls -d
executes ls -d
to all the arguments given. 2>/dev/null
gets rid of the stderr messages.
If you have GNU xargs
, use -d '\n'
to ensure that filenames (including directories) with embedded spaces are handled correctly, by splitting the input into whole lines rather than also by intra-line whitespace.
echo 'a.txt
does/not.exist
b.txt' | xargs -d '\n' ls -1df 2>/dev/null
Note:
The ls
command emits an error for each non-existent input path, which 2>/dev/null
ignores, while echoing existing paths as-is.
Option -1
prints each path on its own line, -d
prevents recursing into directories, and -f
prevents sorting of the input paths (if you actually want sorting, omit the f
).
On macOS/BSD, xargs
doesn't support -d
, which requires a workaround via NUL-separated input using tr
and xargs
's -0
option:
echo 'a.txt
does/not.exist
b.txt' | tr '\n' '\0' | xargs -0 ls -1df 2>/dev/null
As a one-liner, and pure bash for speed (improved from mklement0's answer, would have commented if I'd had the rep):
{ ls; echo does/not.exist; } | while IFS= read -r f; do [[ -f "$f" ]] && echo "$f"; done
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With