6

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?

11

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.

| improve this answer | |
  • 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
4

Why not use the find command ?

find . -name YOUR_SEARCH_NAME -type d
| improve this answer | |
  • 6
    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
3

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 {} +
| improve this answer | |
  • 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.
| improve this answer | |
  • Yeah root access for a task like this should really be avoided. – shrx Apr 3 '12 at 20:32
1

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

# locate directories:
# -------------------
locd () {
    locate $1 | xargs -I {} bash -c 'if [ -d "{}" ]; then echo {}; fi'
}

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

| improve this answer | |
  • 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
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

| improve this answer | |
0

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
| improve this answer | |
  • Can you explain what the echo ${line##*/} is doing? – user128063 Nov 9 '18 at 20:24

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.