Monday, April 5, 2010

Useful command line little tricks (part 5)

Today I want to cover command line search applications. These applications are interesting and useful, and as you shall find out, incredibly powerful!

LOCATE

Sometimes regarded as "the easy way" to search from the Linux command line, locate does exactly as one would expect: it returns the location of a given file/folder. In my opinion, its biggest advantage is that it is fairly simple to use, and very quick! To see a simple example, let's try to locate jpg files (images) in our computer. In order to do so, run the following command:

locate *.jpg

Wow! That was fast, huh!? Locate returned all jpg files in your drive in an instant. If you are used to how Windows searches from the GUI, this probably felt like the speed of light!

OK, that was good, but how about locating something less straight forward, maybe an obscure filename that may not be as common as jpeg files? For example, say you have been experiencing issues with your X session and need to check the Xorg logs:

locate Xorg

Once again, a list showing absolute paths to all files containing the word "Xorg" is returned. As correctly pointed out by the locate command, Xorg logs reside under the /var/log folder.

You probably noticed that those results were once again returned very quickly. This is the case because locate does not actually search your drive, but a database of its own. The downside to this approach, though, is that the locate database is updated only so often. That means that if you created a file just some seconds ago, locate will most likely not find it, for it needs to index it first. Having said so, you can manually update that database at any given moment, just running the following command (as root or using sudo):

updatedb

For those who don't particularly like using the command line interface, I have put together a very simple script you can use to get the benefits from this command without actually having to interact with the shell every time you do use locate.

NOTE: As usual, this is aimed at Ubuntu users, but it should work on any GNOME distro. As for KDE distros, you can use kdialog with just a few minor changes.

First off, open gedit or any other text editor of your choice, then copy and paste the text below on a new text document:

#!/bin/sh

zenity --info --text "$(locate "$(zenity --entry)")"


Once done, save the file as "search" under your home folder, which should be the default saving location anyways.

Now, close gedit and browse your home folder to ensure the search script was successfully created. Bingo! The file is there, all we need to do now is grant it executable rights, so it can be run from a desktop launcher. Simply open a terminal and run the following command:

chmod 744 search

That's it, you can close the terminal window now.

Let's create a launcher in a location of our choice. For the purpose of this example, I chose the desktop.

First, right click on your desktop and add a new launcher.


I created a launcher and pointed it to my "search" script

Obviously, you can customize the icon, launcher name, comments, etc. Once you are done, simply close that window and double click on your newly created launcher. If everything went as expected, you should get a popup prompt, like this one:


Using our previous example, I am searching for "Xorg"

Enter your search term and click OK. The result will come back very quickly, as shown below:


The results from our search!

As you can imagine, this is a very simple script which lacks the flexibility of using locate straight from the command line. Having said so, you can obviously modify the script I provided and add certain parameters to the locate command so that it fits your needs better.

FIND

We just saw locate is a very interesting command with some powerful features, albeit limited for the kind of power we would expect from the command line. We are going to quickly see some examples of that power though, through the use of the find command.

Unlike locate, find is not very intuitive. In my opinion, not even the help included with this command is really that helpful for beginners, so it takes a while before you grasp how things go. Essentially, the main thing to understand about find is that, unlike locate, it does not expect a file or folder name as input. The input for find is made of search criteria, which can be very diverse, thus making it very powerful.

To show how find works, let's just use an example, namely the same one we tried with locate.

find "/" -type f -name "*.jpg"

Note that find will default to the path you are at, as opposed to locate, which covered the whole tree structure. Because of that, we pass / (the root of the folder structure) as the first parameter. Then, we specify that the element we are after is of type "file". As a last step, we provide a pattern for the name to match.

Some of the criteria we can use includes: creation date, modification date, owner, group, type, name, readable, writable, executable, size and many, many more! Therefore, we can go from "search for any file with .jpg extension" type search to "find me any element under root of type file which belongs to user A, group B, that is a month or older, was modified in the last 5 days, has writable permissions and .jpg extension, or maybe one that was created in the last 5 minutes, has .log extension and is empty. Once you find any of those, delete them". Wow!! Now try achieving that from the GUI, it would take forever!

Let's see how this works:

The find command includes three main elements: tests, operators and actions.

Tests

This is the only element we have seen in examples so far. When we pass find a specific type, name, a group or a user, we are essentially passing tests. Let's try an example that shows a bit more of find's real power using tests:

find -type d -empty -mtime +30

The command above returns empty folders which have not been modified in the last 30 days. A variation of this command may help us find opportunities for cleaning up our home folder.

find -type f -size +20M -user A -executable

This would find files with execution rights, size 20MB or larger, which belong to user A.

find -mindepth 2 -maxdepth 3 -type f | wc -l

This would return how many files there are inside the folders stored in your home folder.

Options

As you probably realized from the tests we have just seen, they cover a lot of ground. However, sometimes these tests may fall short and you may need even more flexibility. Let's see some examples:

find \( -maxdepth 1 -type f -size +20M \) -or \( -maxdepth 1 -type d -empty \)

Alright, so we are now finding files of size 20MB or larger, or empty folders, both of which must live in our home folder directly. Note that we are escaping (adding "\" in front of) parenthesis to avoid that the shell interprets them.

Options allow us to add logic to our find structures. In other words, we can construct tests further, making them more complex and powerful.

find -size +20M -not \( \( -user A \) -or \( -user B \) \)

The command above would return files 20MB or larger which do not belong to neither user A nor B.

Actions

That's all very nice, we can search based on almost any criterium we can think of, but what if we could actually act upon what we find? That would make find a number of magnitudes more powerful!

As it turns out, find does allow us to action upon our search results. There are some actions predefined, and a way to create our own actions. Let's see some examples:

find -type f -size +20M -user A -executable -delete

This would delete files that match the corresponding test.
(Warning: Use delete with caution!)

find -name "*config*" -ls

This runs the equivalent to "ls -dils" over the output find returned.

Now, I will create my own customized action for the final example:

find -mtime +30 -size +10M -type f -name "*.mp3" -exec xmms '{}' ';'

This neat command would find mp3 files 10MB or larger, which have not been modified in the last 30 days, then play them with XMMS (Winamp clone) sequentially. (NOTE: special characters or bad file naming could keep XMMS from playing).

In this case, I am not going to share a way to run find from the GUI because it would really defeat its purpose. While locate is fairly straight forward and limited, find provides so many options that only an equally powerful visual interface would provide a decent match. Creating such interface is certainly beyond the scope of this article.

SUMMING UP...

As with pretty much anything we have covered in this section, creativity is key to get the most from the commands at our disposal. The find command is probably one of the clearest examples of that, for it allows us to cover lots of ground with a single line of code.

I would like to encourage you to give find a try. It is a bit cumbersome initially, but once you get around its logic and learn some of its most common options, you will find yourself smiling at what you have achieved with it! In addition, please note the examples I used may not make much sense or add much value, it is the power and flexibility of find I wanted to convey.

Good luck and have fun!

3 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. find -mindepth 2 -maxdepth 3 -type f | wc -l

    This example breaks if you have new lines in file names.Rather, something like

    find . -mindepth 2 -maxdepth 3 -type f -exec printf '%.0s.' {} + | wc -c

    would help

    ReplyDelete
  3. Thank you Chema. I am new to Linux Untunbu 10.4. I found
    it was much easier than I thought. I am finished with Windows. I follow your posts keep up the good work, I loved your review Windows's 7 V Linix Untunbu 10.04,

    ReplyDelete