9

On a UNIX system, "locate" searches the database for files with chosen name or files within the folder with the chosen name. How can I use locate to output only folders, not files?

1

10 Answers 10

12

Actually, locate has what it takes if you use the --regexp option and you don't mind it spitting out files that have the same name as the directories you seek. The "end of line" position marker gets the job done:

locate -r '/dirname$'

locate also supports --ignore-case if that's what you want.

7
  • To search for all directories, locate -r '/[^\.]*$'. – Mateen Ulhaq Feb 17 '18 at 23:26
  • Mateen's approach doesn't filter for directories. It returns everything in the database. The OP was looking for a specific directory and seems to know the name of the directory he wants. – Frank M Apr 3 '18 at 21:33
  • Doesn't work if dirname is in the middle of the dir name. – CodyChan Feb 9 at 18:56
  • @CodyChan: I was assuming "dirname" is the entire directory name. Can you show an example where this doesn't work? – Frank M Feb 10 at 22:38
  • string is part of the directory name such as I need to search directory whose name contains def such as directory "abc_def_ghi" since most of the time I need to locate a directory containing a string, just like locating a file containing a word but it is a directory. – CodyChan Feb 12 at 17:54
4

Why not use the find command ?

find . -name YOUR_SEARCH_NAME -type d
1
  • 7
    locate is faster and I don't need it to be up to date all the time for my purpose. – shrx Apr 3 '12 at 20:30
4

locate itself can't do it for you. So the UNIX way to do it is to filter the output of locate:

locate --null something | xargs -r0 sh -c 'for i do [ -d "$i" ] && printf "%s\n" "$i"; done' sh {} +
7
  • 5
    That command just rebooted my machine (I had a /tmp/something$(reboot) file). – sch Apr 1 '15 at 13:09
  • 2
    @sch Wow, that sucks – Der Hochstapler Apr 2 '15 at 8:39
  • The proper way is with something like locate --null something | xargs -r0 sh -c 'for i do [ -d "$i" ] && printf "%s\n" "$i"; done' sh {} +. {} should never be embedded in the shell code, that's as bad as using eval with arbitrary data (hence the downvote). – sch Apr 2 '15 at 9:05
  • Note that [ -d also returns true for symlinks to directories. Not necessarily bad, just worth noting as it's different for instance from find -type d. – sch Apr 2 '15 at 9:12
  • 1
    @sch: Well, if you don't understand the consequences and if you're in the habit of having files named $(reboot) on your computer, maybe you shouldn't run commands you find on the internet with sudo ;D But, thanks for providing a better version, feel free to edit or post it as an answer, so it doesn't get lost in comments. – Der Hochstapler Apr 2 '15 at 9:56
2

find as suggested in Scott Wilson's answer is what I would have used. However, if you really need to use the locate DB, a hackish solution could be

sudo strings /var/lib/mlocate/mlocate.db | grep -E '^/.*dirname'
  • sudo since the database is not directly readable by regular users.
  • strings to strip metadata (this makes you also find directories to which you don't have read permission, which locate usually hinders).
  • /var/lib/mlocate/mlocate.db is the DB path on Ubuntu, apparently (as an example. Other distributions might have it in other places, e.g. /var/lib/slocate/slocate.db).
  • grep -E to enable regular expressions.
  • ^/.*dirname will match all lines that start with a /, which all directories in the DB happen to do, followed by any character a number of times, followed by your search word.

Positive sides of this solution:

  • it is faster than find,
  • you can use all the bells and whistles of grep (or other favourite text processing tools).

Negative sides:

  • the same as locate in general (DB must be updated),
  • you need root access.
2
  • Yeah root access for a task like this should really be avoided. – shrx Apr 3 '12 at 20:32
  • Does this list matching files as well as matching directories? – joeytwiddle Dec 22 '20 at 6:07
2

Putting Oliver Salzburg's neat line into your .bashrc:

# locate directories:
# -------------------
locd () {
    locate -0 -b -A "$@" | xargs -0 -I {} bash -c '[ -d "{}" ] && echo "{}"'
}

then you can type locd something everytime you want to locate just directories.


Some breakdown:

  • -0 provides better support for filenames containing spaces or newlines.

  • -b or --basename matches only the last part of the path.

  • -A matches all inputs, so if you provide multiple arguments, all must be present.

2
  • For me, to handle spaces in directories better, I use the following: locate -i --all $1 | xargs -I {} bash -c 'if [ -d "'"{}"'" ]; then echo "'"{}"'"; fi' – user128063 Nov 9 '18 at 20:30
  • Use locate -0 and xargs -0 flags if you get the xargs unterminated quote error. – usr122212 Dec 25 '19 at 1:53
1

I went with this solution:

locate -i "$foldername" | while read line
        do
            if [[ -d "$line" && `echo ${line##*/} | tr [:upper:] [:lower:]` = *`echo $foldername | tr [:upper:] [:lower:]`* ]]; then
                echo "$line"
            fi
        done
1
  • Can you explain what the echo ${line##*/} is doing? – user128063 Nov 9 '18 at 20:24
0

Place these as last lines or where ever it fits best for you.
gedit ~/.bashrc

#system only
slocate() { locate $@ | egrep -v ˆ/home ; }

#system directories only
dslocate() { for directory in `locate $@ | egrep -v ˆ/home`; do if [ -d "$directory" ]; then echo $directory; fi; done ; }

#whole system directories only
dlocate() { for directory in `locate $@`; do if [ -d "$directory" ]; then echo $directory; fi; done ; }

#local user's only
llocate() { locate $@ | egrep ˆ/home ; }

#local user's directories only
ldlocate() { for directory in `locate $@ | egrep ˆ/home`; do if [ -d "$directory" ]; then echo $directory; fi; done ; }


hope this helps, cheers

0

I know this thread is a little old but mlocate's limitations always bothered me too. I finally created my own version of slocate/mlocate called blocate that uses sqlite for indexing and lets you index anything you want using a find command. Performs really well and manages parallel indexing+searching with sqlite in just about 30 lines of bash. GPL - feedback welcome.

https://github.com/jboero/blocate

Hope this helps someone. I built a personal archive website for my backups indexing with mlocate but I got tired of searches taking forever and I didn't want to build a full database solution around it. My searches have gone from ~10s or so down to about 300ms.

0

This answer is the inverse of this other. Use

file $(locate -r 'xfce4-keyboard-overlay$') | grep directory$ | awk -F: '{ $(NF--)=""; print }'

Explanation:

  1. locate ... finds all files and directories
  2. file $(...) appends a message at the end of each line with the type of file
  3. grep ... filters lines containing directory$
  4. awk ... removes what file ... appended
0

A small variation on others

for f in $(locate /dirname | grep /dirname$ ) ; do if [ -f $f ] ; then ls -1 $f ; fi ; done

If you want to match a pattern instead of providing the full name, there are also variations with grep.

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.