From shell script to compact tool

Sometimes you need things fast; when the search for a needed tool leads to a dead end, a knowledgeable Linux user can usually cobble together a program with a few lines of shell code. However, putting a bit more time into the quickly developed script could result in a robust program.

One example is the famous Windows "Snipping Tool" that captures sections of a screen and opens, saves, or copies them to the clipboard for use in another program. The same function is easily programmed in Linux. With a bit of effort, you can create a full-fledged tool that you can integrate into your desktop as a keyboard shortcut or as an item in the start menu or taskbar.

Roll Your Own

The basis for the present project is the import tool  [1] from the powerful ImageMagick  [2] command-line graphics suite. The introduction on its man page is enough to give you an idea of its capabilities: It captures a single window, the whole screen, or any rectangular portion thereof and saves it as a graphics file or sends it to standard output, from which you can pipe it to another command.

If you run import abc.jpg on the command line, the cursor changes to a crosshair, with which you make your selection. The tool then takes a screenshot and saves it in the abc.jpg file.

Other screenshot tools that are already integrated into many desktops usually accept only a few graphics formats, such as JPG or PNG. A further limitation of these tools is that they're likely to be linked to the specific desktop framework and, in some cases, won't allow you to select part of a window. Also, some tools require two or three steps to complete the screenshot.

This entire process can be handled in one step – with a keyboard shortcut, an item on the taskbar, or via the desktop start menu – by grabbing a graphic area, then automatically saving it and even handing it on to another program. One application of the script might be when you're reading a particularly interesting web page and want to capture and save just a portion of it, preferably to a program or test folder created for the purpose, before moving on.

Because the import command is a powerful tool, it's just asking for a shell script to provide just such a solution (Listing  1) [3]. Like any good script, it begins with a line specifying the interpreter to be used. Its exact path appears after the #! . Bash is always a good choice for such tasks. In lines  2 and  3, you set the variables for the paths to use, with the folder in which you want to save the graphics. To enable automatic assignment of a file name, you can start it off with a sequentially generated number.

Listing 1

Simple Script

01 #!/bin/bash
02 path=<home-directory>/Programs/pic-cutter
03 pix=<home-directory>/Pictures/Imports
04 declare -i number
05 number=$(cat ${path}/picnumber)
06 import ${pix}/${number}.jpg
07 let number++
08 echo $number > ${path}/picnumber

The statement in line  4 creates an integer variable that you can increment. During program execution, the script reads in this integer from a file or writes the value incremented by 1 .

To begin, you need a file that contains a number. Instead of opening an editor, enter

echo 1 > Programs/pic-cutter/picnumber

in a terminal to create the required file.

In line  5, you read this integer with a simple cat command. Because the statement is in parentheses, Bash runs the command in a subshell and saves the output in the number variable. The import follows this operation.

Instead of a name for the picture file, the script combines the path stored in the pix variable along with the number and an appended .jpg . The curly brackets around the names ensure that the shell uses the values stored therein, gives the picture a number, and saves it in the desired directory. The command in line  7 increments the integer by 1 . The simple echo command in line  8 writes the new value to the picnumber file.

Variations

If you want to perform a specific task with an image, you could output another graphics format, or you might want to "snip" a particularly interesting passage of text and pipe it to Ocrad  [4], an optical character recognition program, so that you can convert the graphics file into a text file. In this case, it is necessary to work with some less common formats, such as PBM, PGM, and PPM, and not saving the graphic but writing it to standard output.

At this point, of course, you wouldn't want to leave things as they are, because you would always need to call the script from the command line. Instead, it would help to have a keyboard shortcut that points to the script. With Gnome, this is possible with System Settings | Keyboard | Shortcuts . With KDE, use System Settings | System Management | Keyboard Combinations . As a rule, all graphical interfaces have a way of configuring or recreating these keyboard shortcuts.

With regular use of the small batch program, you will realize that it is indeed behaving very much like a full-fledged desktop tool, but with a few ragged edges. Now is the time to extend it as desired.

Even More Robust

In the next step, you'll see how to extend the script so that it can be easily transferred to another system. So far, the script is fairly simple and therefore prone to error. For example, if you were to pass it on, the script would return an error because home directories on other PCs are different.

Listing  2 shows an enhanced version of the snip tool. In line  2, you'll notice the first extension to the code in the acceptance of a parameter, which it references as $1 or ${1} .

Listing 2

Enhanced Script

01 #!/bin/bash
02 GRPROGRAM=${1:-nothing}
03 PICTURES=~/Pictures
04 TARGET=${PICTURES}/Imports
05 BNR=$(date +"%Y-%m-%d_%H%M%S")
06 FMT=jpg
07 PICNAME=ImportedPic-${BNR}.${FMT}
08 CONFIG=~/.config/sniprc
09 [ -f ${CONFIG} && source ${CONFIG} ]
10 [ -d ${TARGET} ] || mkdir -p ${TARGET}
11 import ${TARGET}/${PICNAME} && which ${GRPROGRAM} &>/dev/null && ${GRPROGRAM} ${TARGET}/${PICNAME}

If you don't want to attach a parameter, the :-nothing extension provides a fallback value. If you don't pass in a parameter, it takes the string nothing as the value. That's necessary to avoid an error later on.

The variables in all caps in lines 3 through 6 are used to save pathnames and file names. The use of caps makes the code clear: As a rule, these variables won't change during the course of the program.

The date command in line  5 helps to create a clear and continuous naming convention for the images. The formatting string after the plus sign ensures that the four-digit year, month, day, and time (in seconds) are included in the file name. Line  6 specifies the desired suffix for the images, which determines the file type. Line  7 builds the image file name.

The composite expression in line  4 defines where the script saves the images. But, because the program won't know if this folder even exists, it checks later on to see whether it's been created. If not, it creates it on its own.

Line  8 shows the path to a configuration file for the user. The script checks in line  9 whether the file exists and then reads it. This leaves you the task of designing the script so that it contains sensible defaults, but the individual user has the option to overwrite it without touching or copying the script.

In line  10, the script checks whether the target directory for the images exists. If this is not the case, it creates it. The -p option for the mkdir command ensures that it recursively grabs all higher directories.

Line 11 initiates the import action. The command includes no options. Without a parameter, the script simply imports your "snip" and saves it in the specified folder with the name generated in lines 5-7. If you run the script with a parameter (e.g., gimp ), it checks with the which ${GRPROGRAMM} command in line 11 to see whether the input parameter is a regular path to an executable file. If it is, your image will be opened with this program and further processing of the image file is possible immediately.

Conclusion

With this small script, you have a full-fledged desktop application in your pocket. You can continue to extend it when needed, and you can even port it over to other systems.

One way to extend the script would be simply to add a few options to the import command. For example, you can add -snaps 3 after the command to take a sequence of three screenshots, and from which the import command automatically generates names for the image files. The man page for import provides further advice about the options you can add to the command.

The Author

Goran Mladenovic is not a typical programmer. He speaks several foreign languages and has mastered some programming languages, too.