Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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
tstdir
|-- 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?

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

2 Answers 2

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*'
share|improve this answer
    
This messes up the output from tree though. –  slm Dec 22 '12 at 1:02
    
@sim - In what way? –  ire_and_curses Dec 22 '12 at 1:17
    
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
add comment
up vote 0 down vote accepted

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.

BUGS
   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
   printing.

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

EDIT #1

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*

or

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
  done
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:

resultList=("${!array[@]}")
[ -d "$resultList" ] || unset $resultList

(This would be a lot quicker than

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

)

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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