74

I know I can do this to get a list of directory names:

find . -type d -maxdepth 1 

The output looks like this:

.
./foo
./bar

I prefer the listing without ./. Is there a way to get find to output just the raw names?

I tried sending the list to stat to format it but that just gives me the same result:

find . -type d -maxdepth 1 -print0 | xargs -0 stat -f '%N'
3
  • so you want foo bar ... all on one line without the ./ in front?
    – Levon
    Commented Aug 24, 2012 at 13:22
  • Is this purely for cosmetic / aesthetic reasons or are you trying to do something with the output?
    – jw013
    Commented Aug 24, 2012 at 13:29
  • a note that doesn't answer the question (already well answered): on recent versions of find, you will get a warning if you use a global option like -maxdepth 1 after an argument like -type d; it is now recommended to reverse the order to find . -maxdepth 1 -type d
    – Dalker
    Commented Jul 30, 2021 at 17:32

9 Answers 9

78

With GNU find you can use the -printf option:

find . -maxdepth 1 -type d -printf '%f\n'

As noted by Paweł in the comments, if you don't want the current directory to be listed add -mindepth 1, e.g.:

find . -mindepth 1 -maxdepth 1 -type d -printf '%f\n'
3
  • I cannot find any mention of the -printf option in the latest POSIX spec and I wonder how portable it is ...
    – rahmu
    Commented Aug 25, 2012 at 13:37
  • @rahmu: This was tested with GNU find. None of the printf options are mentioned by POSIX and they do not seem to be supported by some of the other find versions. GNU find can be installed in most places, so in that sense it is portable.
    – Thor
    Commented Aug 25, 2012 at 13:52
  • 5
    also add -mindepth 1 if you want to get rid of the . Commented Sep 26, 2017 at 9:20
23

Update:

A shorter alternative:

 find . -maxdepth 1 -type d | cut -c 3-

Will give you the names, one per line, without any slashes

4
  • 10
    @downvoter .. a downvote without explanation doesn't help anyone (OP, SO or me). This is a functional solution to OP's question. I am happy to correct an error if pointed out or improve the answer, but that requires constructive feedback rather than just an anonymous "click".
    – Levon
    Commented Aug 24, 2012 at 14:02
  • 2
    I'm the one who downvoted when your answer included parsing ls. At the same time I had posted a link on why this is a bad idea on another answer that got deleted since. At the time there were only 2 answers and the reason seemed obvious. I'm glad you pointed out the ambiguity, and here's my explanation. For the record, I turned my downvote in an upvote because I agree with your current answer.
    – rahmu
    Commented Aug 25, 2012 at 13:30
  • @rahmu Giving an explanation for your downvote in another question is not helpful to me (and only obvious to you). Also, while this is a better solution, the solution I had posted before worked just fine (yes, I am familiar with your "don't use ls" link - but it doesn't apply blindly in all cases). If you have a counter example for why my initial solution wouldn't have worked, I'd love to know it (so that I can actually learn something from this), otherwise you are just posting a link and not offering anything constructive.
    – Levon
    Commented Aug 25, 2012 at 16:33
  • Consider there's a \n in a directory name you cannot use cut to retrieve it (which is what you were doing when I downvoted you). There are few cases where ls doesn't behave dangerously and it's almost always safer to use another way.
    – rahmu
    Commented Aug 25, 2012 at 17:17
9

Using GNU find, you can use -mindepth to prevent find from matching the current directory:

find . -type d -maxdepth 1 -mindepth 1

Since you are not doing this recursively, you can use a bash glob:

echo */

Adding a trailing / to a glob will cause only directories to be matched.

2
  • 1
    */ misses dot files and includes symlinks. This may or may not be a problem. Commented Aug 24, 2012 at 23:18
  • @Gilles - It will always miss symlinks, but dotfiles depends on whether or not dotglob is set.
    – jordanm
    Commented Aug 25, 2012 at 0:16
8

I'd rather use:

 find ./ -type d -maxdepth 1 -exec basename {} \;
6

Let sed remove those two characters:

find . -maxdepth 1 -type d | sed -e 's/^\.\///'
0
2

I usually use:

find * -type d

But I don't know if it's the right way to do what you want.

3
  • 1
    If you are going to let the shell expand all the filenames, why use find at all?
    – jordanm
    Commented Aug 24, 2012 at 16:14
  • @jordanm To select only directories. echo */ would do the same thing, more or less (it misses dot files and includes symlinks), but then joachim would ask how to remove the final /. Commented Aug 24, 2012 at 23:17
  • Contrary to other answers, a "find *" will miss any "hidden dirs" (dirs whose name starts with a .)
    – Dalker
    Commented Jul 30, 2021 at 17:28
0

In AIX does the parameter 'maxdepth' not work.

In general this works for me:

find ./ -type d | cut -d"/" -f2 | sort -u

0

What you are looking for is called basename, it ignore the unix directory structure

Example below:

find /any/path/you/want -maxdepth 1 -type d -exec basename {} \;

it will exclude for the output even the dir path, removing the necessity to cd before run the command


Some aditional info:

I'd pass -exec as argument to find instead |(pipe) another command for the output (avoiding the second command go over each output line, having said that, depending on the output it could improve the performance for the script)

NOTE: find options are not positional (-maxdepth affects tests specified before it as well as those specified after it).

0

Another alternative

find * -type d -maxdepth 0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .