I'm trying to figure out if there is a way to get the UNIX command tree to display only directories that match a specific pattern.

% tree -d tstdir -P '*qm*' -L 1
|-- d1
|-- d2
|-- qm1
|-- qm2
`-- qm3

5 directories

The man page shows this bit about the switch.

-P pattern List only those files that match the wild-card pattern. Note: you must use the -a option to also consider those files beginning with a dot .' for matching. Valid wildcard operators are*' (any zero or more characters), ?' (any single character),[...]' (any single character listed between brackets (optional - (dash) for character range may be used: ex: [A-Z]), and [^...]' (any single character not listed in brackets) and|' sepa‐ rates alternate patterns.

I'm assuming that the bit about ...List only those files... is the issue. Am I correct in my interpretation that this switch will only pattern match on files and NOT directories?

  • 1
    what you want to accomplish ? have you tried find tstdir/ -type d -iname "qm*" or tree -I "d*" -d tstdir/ Dec 21 '12 at 20:44
  • Directories are technically also files, but a special kind of file.
    – bahamat
    Dec 22 '12 at 9:22

There's no way for tree to do this on its own. Patterns are not applied to directories, only files.

However, you can easily accomplish what you want by getting the directory listing with tree, and then applying the match pattern with grep.

tree -d tstdir -L 1 | grep '*qm*'
  • This messes up the output from tree though.
    – slm
    Dec 22 '12 at 1:02
  • @sim - In what way? Dec 22 '12 at 1:17
  • 1
    The ASCII line graphics that show the directory structure. Admittedly this isn't a huge deal but I thought I'd mention it.
    – slm
    Dec 22 '12 at 1:20

Someone mentioned on stackoverflow in the trees man page that this is why the -P switch doesn't exclude things that don't match the pattern.

   Tree  does not prune "empty" directories when the -P and -I options are
   used.  Tree prints directories as it comes to them, so  cannot  accumu‐
   late  information  on files and directories beneath the directory it is

So it doesn't appear to be possible to get tree to filter its output using the -P switch.


From a question I had posted on SO that got closed. Someone, @fhauri, had posted the following information as alternative ways to accomplish what I was trying to do with the tree command. I'm adding them to my answer here for completeness.

-d switch ask to not print files:

    -d     List directories only.

So if you WANT use this, you could:

tree tstdir -P '*qm*' -L 1 | grep -B1 -- '-- .*qm'
|-- id1
|   `-- aqm_P1800-id1.0200.bin
|-- id165
|   `-- aqm_P1800-id165.0200.bin
|-- id166
|   `-- aqm_P1800-id166.0200.bin
|-- id17
|   `-- aqm_P1800-id17.0200.bin
|-- id18
|   `-- aqm_P1800-id18.0200.bin
|-- id2
|   `-- aqm_P1800-id2.0200.bin

At all, if you use -L 1,

   -L level
          Max display depth of the directory tree.

you could better use (in bash) this syntax:

cd tstdir
echo */*qm*


printf "%s\n" */*qm*

and if only dir is needed:

printf "%s\n" */*qm* | sed 's|/.*$||' | uniq

At all, you could do this very quickly if pure bash:

declare -A array;for file in  */*qm* ;do array[${file%/*}]='';done;echo "${!array[@]}"

This could be explained:

cd tstdir
declare -A array          # Declare associative array, (named ``array'')
for file in  */*qm* ;do   # For each *qm* in a subdirectory from there
    array[${file%/*}]=''  # Set a entry in array named as directory, containing nothing
echo "${!array[@]}"         # print each entrys in array.

... if there is no file matching pattern, result would display *. so for perfect the job, there left to do:

[ -d "$resultList" ] || unset $resultList

(This would be a lot quicker than

declare -A array
for file in  */*qm*; do
    [ "$file" == "*/*qm*" ] || array[${file%/*}]=''
echo "${!array[@]}"


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.