12

For example, I looking for files and directories in some directory:

ubuntu@example:/etc/letsencrypt$ sudo find . -name example.com*
./archive/example.com
./renewal/example.com.conf
./live/example.com
ubuntu@example:/etc/letsencrypt$ 

How can I mark that ./archive/example.com and ./live/example.com are directories in the output above?

2
  • You can't say that the "example.com" in ./archive/example.com and ./live/example.com is a directory -although you could say that ./archive and ./live are. Do you want to amend your question? May 31, 2021 at 18:15
  • 3
    @JeremyBoden, the answers below are what I need. I don't want to amend my question. May 31, 2021 at 20:50

5 Answers 5

35

Print the file type along with the name with -printf "%y %p\n":

$ sudo find . -name 'example.com*' -printf "%y %p\n"
d ./archive/example.com
f ./renewal/example.com.conf
d ./live/example.com

The use of -printf assumes GNU find (the most common find implementation on Linux systems).

24

Find twice:

echo 'directories'
find . -name 'example.com*'   -type d

echo 'non-directories'
find . -name 'example.com*' ! -type d

Note too the quoting of the pattern used for the name test. Without quotes, the shell would try to match the string against names in the current directory before calling find. If the failglob shell option was set in the bash shell, or if the NOMATCH shell option in zsh was not unset, an unquoted globbing pattern that didn't match anything would generate an error from the shell, and find would not be called at all.


Alternatively, just output a slash at the end of the directory pathnames (this is how ls -p would represent directories):

find . -name 'example.com*' \( -type d -exec printf '%s/\n' {} \; -o -print \)

The above find command first tests that the name is correct. If it is, and it's a directory, it calls printf to output the pathname of the directory with a slash at the end. If it's not a directory -print is used to just output the pathname as is.

With GNU find, the -exec printf '%s/\n' {} \; bit could be replaced by -printf '%p/\n'.

With standard find, you could also use -exec printf '%s/\n' {} + to call the external printf utility as few times as possible, but this would mean that directories likely would be outputted last, or at least in batches.


Another alternative is to actually use ls -p to tell directories apart from other file types. Using ls -p, a directory would be listed with a trailing / character, just as above.

find . -name 'example.com*' -exec ls -f -d -p {} +

I'm using -f here to avoid letting ls sort the output, and -d to avoid listing the contents of directories.

You could use ls -F instead of ls -p to also put other marks on file types other than directories. For example, executables would be suffixed by * and symbolic links would be suffixed by @.

Both -p and -F (and -f and -d) are standard options to the ls utility.

1
  • 2
    This one has the advantage over the accepted answer of working regardless of which find implementation you're working with.
    – Shadur
    Jun 1, 2021 at 12:22
7

You can use file like that:

sudo find . -name "example.com*" -print0 | xargs  -0 sudo file

Example output:

$ sudo find .  -name "example.com*"   -print0 | xargs  -0 sudo file
./example.com. big file: ASCII text
./example.com-dir:       directory
./example.com:           empty
4

I would call an ls on it:

# find . -name example.com\* -print0 | xargs -0 ls -ld

If you need to do the find and ls as root and you aren't then you could do:

# sudo bash -c "find . -name example.com\* -print0 | xargs -0 ls -ld"

The number of backslashes before the asterisk * may depend on your shell - perhaps you need 0 or 1 of them inside the quotes "".

4
  • 2
    GNU & FreeBSD versions of find (and probably others) have a -ls option, so there's no need for xargs (in fact, there's rarely ever a need to pipe find into xargs, -exec is built-in to find). find . -name 'example.com*' -ls. The output is very similar, only slightly different, to running ls -l. Ubuntu, of course, has GNU find.
    – cas
    May 30, 2021 at 18:18
  • @cas Thanks. I wanted to use the -d option to ls so I suppose I need to call it, or does the built-in ls have the same options? I use xargs because it is more generic.
    – Ned64
    May 30, 2021 at 18:24
  • With GNU find / ls you could just do find . -name 'example.com*' -exec ls -dp {} + (the -p or --indicator-style=slash option appends a slash indicator on directories; -d prevents descending into them) May 30, 2021 at 20:46
  • 1
    you don't need -d with find's -ls option. it will only show matched files/dirs, not the contents of dirs (unless those contents match, of course). try it and see: find . -maxdepth 1 -type d -ls
    – cas
    May 31, 2021 at 2:15
2

If you want a more portable option that will work with *nix flavors without the gnu -printf option (macOS for example) you can add a slash to the end of directory paths via ls like so:

find . -name "example.com*" -exec ls -dF {} \;

example:

$ sudo find . -name "example.com*" -exec ls -dF {} \;
./archive/example.com/
./renewal/example.com.conf
./live/example.com/

This also happens to be in a format more suitable for further piping to more unix commands.

2
  • Note that -F also adds other characters to other file types (making it hazardous to pipe these into further commands). I've already mentioned this in my own answer.
    – Kusalananda
    May 31, 2021 at 8:39
  • Good point! I missed that part of your answer, thanks for pointing it out.
    – Mat Bess
    May 31, 2021 at 8:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.