0

I'm looking to list only files and directories and no extra data. It's used for parsing the data and I don't need the extra items of file size, permissions...etc.

TIA

Dale
  • 1,183

3 Answers3

2

It's used for parsing the data

Parsing – but how?

If you're parsing in a shell like this:

# don't
for f in $(dir); do my_parser "$f"; done

then this is Bash pitfall number one. In such case use for f in ./*; do ….

From now on I assume you're parsing by piping, like this: dir | my_parser.


Do not parse the output of ls/dir

Your dir (from your answer) is probably just ls -C -b. As you shouldn't parse the output of ls, you shouldn't parse the output of dir either.


You can parse the output of find

You can pipe find to a parser. Pathnames containing newlines will be misinterpreted while parsing. To parse reliably use GNU find with -print0. This will terminate each pathname with a null character (instead of a newline character). Pathnames themselves cannot contain null characters, so there will be no ambiguity. POSIX solution is -exec printf '%s\0' {} +. Purely POSIX tools usually expect text files as input and they may not accept null characters, but if your parser can accept null-terminated strings then this is how you can generate them from find that doesn't support -print0.

find descends to subdirectories by default. With GNU find you can change this by specifying -maxdepth 1. A solution for POSIX find is here: Limit POSIX find to specific depth. If the starting point is . then the solution is \( -name . -o -prune \).

find starting_directory prints starting_directory as the first pathname. I guess you'd like not to get this particular pathname. The relevant test is ! -path starting_directory (remember -path treats its argument as a pattern). If starting directory is specified as . then ! -name . will be enough. With GNU find -mindepth 1 is an alternative, it will work regardless of the starting directory.

The final command can be one of the following:

find . -maxdepth 1 -mindepth 1                     # newline-terminated, GNU
find . \( -name . -o -prune \) ! -name .           # newline-terminated, POSIX
find . ! -name . -prune                            # newline-terminated, POSIX, simplified
find . -maxdepth 1 -mindepth 1 -print0             # null-terminated, GNU
find . ! -name . -prune -exec printf '%s\0' {} +   # null-terminated, POSIX

The list is not exhaustive, other equivalent forms exist.

All the above commands generate output where pathnames start with ./ (at least with find implementations I tested, but apparently YMMV). You can remove this prefix by piping to sed 's|^\./||' (when newline-terminated) or to sed -z 's|^\./||' (when null-terminated; note -z is supported by GNU sed but it's not required by POSIX). E.g. like this:

find . ! -name . -prune | sed 's|^\./||'

Keep in mind that any solution using newline-terminated pathnames will fail or misbehave if some pathname contains a newline character.


Maybe you don't even need find

If your parser is written by you in some programming language then you should use whatever way of listing files the language provides instead of relying on standalone executables like ls, dir or find. There should be a totally reliable way to iterate over directory entries.

1

n/m.. found it. Solution: dir

Dale
  • 1,183
0

As you've noticed, dir is a good option that by default is set up to do what you want, but the equivalent command for ls - which, being the more common tool, is probably more widely available on Unix-like systems - is ls -1 (that's the number 1, not a lowercase L).

From man ls:

-1     list one file per line.
Hashim Aziz
  • 13,835