Saturday, February 23, 2013

Splitting up is easy for a PDF file

Occasionally, I needed to extract some pages from a multi-page pdf document. Suppose you have a 6-page pdf document named myoldfile.pdf. You want to extract into a new pdf file mynewfile.pdf containing only pages 1 and 2, 4 and 5 from myoldfile.pdf.

I did exactly that using pdktk, a command-line tool.

If pdftk is not already installed, install it like this on a Debian or Ubuntu-based computer.

$ sudo apt-get update
$ sudo apt-get install pdftk

Then, to make a new pdf with just pages 1, 2, 4, and 5 from the old pdf, do this:

$ pdftk myoldfile.pdf cat 1 2 4 5 output mynewfile.pdf

Note that cat and output are special pdftk keywords. cat specifies the operation to perform on the input file. output signals that what follows is the name of the output pdf file.

You can specify page ranges like this:

$ pdftk myoldfile.pdf cat 1-2 4-5 output mynewfile.pdf

pdftk has a few more tricks in its back pocket. For example, you can specify a burst operation to split each page in the input file into a separate output file.

$ pdftk myoldfile.pdf burst 

By default, the output files are named pg_0001.pdf, pg_0002.pdf, etc.

pdftk is also capable of merging multiple pdf files into one pdf.

$ pdftk pg_0001.pdf pg_0002.pdf pg_0004.pdf pg_0005.pdf output mynewfile.pdf 

That would merge the files corresponding to the first, second, fourth and fifth pages into a single output pdf.

If you know of another easy way to split up pages from a pdf file, please tell us in a comment. Much appreciated.

Two updates (part 2, part 3) are available for this post.

Saturday, July 21, 2012

Convert units of measurement

How do you convert from 1 measurement unit to another unit? Say from kilometers to miles.

I can always look it up on that fridge magnet. This one local realtor likes to send me freebies like the fridge magnet with the common conversion factors.

If you don't have a handy fridge magnet, you can try the units command-line utility program.

To install it on a Debian system, enter:

# apt-get install units

# units 60km miles
 * 37.282272
 / 0.0268224

It tells you that 60 kilometers is equivalent to 37.282272 miles.

The second line (beginning with the '/') is somewhat confusing. It is saying, 60 km = 1 / 0.0268224 miles.

Running units in verbose mode makes it clearer.

# units -v 60km miles
 60km = 37.282272 miles
 60km = (1 / 0.0268224) miles

If you like to put spaces in your search parameters, remember to enclose it with quotes.

# units '60 km'  miles
 * 37.282272
 / 0.0268224

If you just want to know the conversion factors, do this:

# units km miles
 * 0.62137119
 / 1.609344

Very quickly, you know:
1 km = 0.62137119 mile, and
1 mile = 1.609344 km.

To many people, installing units and learning all that syntax may be a little too much work.

You can google the answer.

Simply bring up your web browser and go to the Google search page.

Enter this to search:
60 km in miles

The top item returned is the answer you are looking for.

Google Everything.

Sunday, April 11, 2010

How to insert a file at a specific line and column

My objective is to insert the complete contents of a text file at a specific row and column of another text file.

If we are merely concerned with inserting after a specific line, it can be readily achieved with a number of Linux tools. For example, to insert file1.txt after the second line of file2.txt, any of the following commands will do:

  • $ sed -i '2r file1.txt' file2.txt

  • $ awk '{print} NR==2 {while (getline < "file1.txt") print}' file2.txt

    Unlike the previous sed command which modifies file2 in-line, the above awk command writes the desired output to standard output only.

  • $ emacs -batch +3 file2.txt --insert file1.txt -f save-buffer -kill

    This uses the batch capability of the emacs text editor. The command opens file2 at line 3, inserts file1, saves and then exits.

  • $ vi +2 file2.txt << DELIM
    > :r file1.txt
    > :wq
    > DELIM
    Vim: Warning: Input is not from a terminal

    Note that after you enter the first line ("vi +2 ..."), you will be prompted for more input. At that time, you enter the next three lines (:r, :wq, DELIM)

While Linux has many utilities to manipulate text (sed, perl, awk, cut, python), the easiest way I can think of to accomplish my objective to insert at a target line and column is using emacs.

$ emacs -batch -Q +2:3 file2.txt --insert file1.txt -f save-buffer -kill 2>/dev/null

The key is +2:3 which directs the editor to open the file at line 2 column 3.

Two other components in the above emacs command warrant some explanation. First, -Q means quick startup. Quick, because emacs won't load any init file, or any splash file. Second, the last part of the command pipes any standard error output from the emacs editor to the null device.

I don't doubt that sed, awk or perl can do the job. If you have a simple solution, please share with us via the comment feature of this web page. Many thanks.

Saturday, November 14, 2009

Fun with Date Arithmetic

We all know that the date command tells you the current time. Occasionally, you use the same command to set the time. That however becomes rarer these days with the advent of the ntp service that automatically synchronizes your computer's time with a super accurate public time server of your choice.

Various implementations of the date command are in use today. This article discusses the date command of the GNU coreutils package.

By default, the date command tells you the time now. The date command also lets you do some basic date addition and subtraction. This is achieved by specifying the -d option which displays a time that you entered as a parameter rather than now.

How many times have you asked yourself what the calendar date is N days ago? Just the other day, I needed to find out the precise date of 30 days ago in order to locate the proper log file.

$ date
Sat Nov 14 17:54:51 PST 2009
$ date -d -30days
Thu Oct 15 18:54:56 PDT 2009


Just like you use subtraction to calculate a back date, you use addition to calculate a forward date. The example below displays the date 30 days from today.
$ date -d +30days
Thu Oct 15 18:54:56 PDT 2009


Besides days as the unit, you can also manipulate years, months, hours, minutes, and seconds.
peter@tiger:~$ date -d +2months
Thu Jan 14 18:48:43 PST 2010


You can combine them together like this:
$ date -d +2months17days
Sun Jan 31 18:49:45 PST 2010


Note that all the above are calculated relative to today's date. What about queries like 10 days tomorrow?
$ date -d tomorrow+10days
date -d tomorrow+10days
Wed Nov 25 18:52:03 PST 2009


10 days yesterday?
$ date -d yesterday-10days
Tue Nov 3 18:53:07 PST 2009


You can also perform your arithmetic relative to a specific day, say January 21, 2010.
$ date -d '2010-01-21 + 2 weeks 3 days'
Sun Feb 7 00:00:00 PST 2010


Lastly, the date command also recognizes the day of weeks (Sunday, Monday, ...) and the 2 keywords "last" and "next".
$ date -d 'next tuesday + 1 day'
Wed Nov 18 00:00:00 PST 2009


I hope you have fun with this versatile tool.

Friday, July 17, 2009

How to move print jobs from one printer queue to another

In the olden days, an entire office department shared one printer. At home, an entire household shared one printer. Nowadays, I have 2 printers at home (1 HP LaserJet and 1 Samsung Monochrome Laser printer).

With access to multiple printers come new opportunities and challenges. One of those opportunities is that if one printer goes down for whatever reason, you can route your print jobs to the surviving one. One challenge is that you need to manage multiple printer queues. With more than 1 printer, I often find myself printing to the wrong one. How do you route print jobs from 1 printer to another when the need arises?

Job Submitted to Wrong Printer


Let's first consider this situation: you just submit your print job to the default printer(mySamsung), but you realize after the fact that it is the wrong printer.

First, you should find out the print job number. Run the familiar lpq command.
$ lpq -P mySamsung
mySamsung is ready and printing
Rank Owner Job File(s) Total Size
active peter 706 (i) 100352 bytes
1st peter 707 MoviesReview 228352 bytes
$

Note that given mySamsung is my default printer, I don't really need to explicitly specify the printer: lpq without any argument will do just fine.

Say job 707 is the one you want to move to the other printer.

The Linux command to do the actual migration is lpmove. Note that you need to run the command as root.

$ sudo lpmove mySamsung-707 myHP
$ lpq -P myHP
myHP is ready
Rank Owner Job File(s) Total Size
active peter 707 MoviesReview 228352 bytes

Note how I specified the job number to lpmove. The format is the printer name(mySamsung) and a dash(-), followed by the job number (707).


Printer Down


Suppose mySamsung is out of service for whatever reason. Then, you need to move all print jobs from mySamsung to myPrinter.

$ sudo lpmove mySamsung myHP
$