Pantry User Guide

Omari Norman

Version 32 released Saturday, March 14, 2009.

Copyright 2007-2009 Omari Norman.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Data in the starter_database file is derived from U.S. Department of Agriculture, Agricultural Research Service. 2008. USDA National Nutrient Database for Standard Reference, Release 21. Nutrient Data Laboratory Home Page: http://www.ars.usda.gov/ba/bhnrc/ndl This data is in the public domain and there is no copyright, see http://www.ars.usda.gov/Main/docs.htm?docid=6233#copyright


Table of Contents

About Pantry
Pantry's advantages
Pantry's disadvantages
Alternatives
Pantry on the Internet
About the documentation
Installation
Install everything you will need to compile Pantry
Compiling and installing
Getting help and reporting bugs
1. The Pantry Paradigm
A client-server model
Foods
Traits
Nutrients
Available units
Collections and databases
2. Manipulating foods
Opening files and getting server status
The name, info, and blank reports
Selecting foods with the --search option
The units report, and changing foods
Making changes permanent
Reports about nutrients
Sorting reports, and using --auto-order
Approximations with the --refuse and --by-nut options
The paste report
Saving and quitting
Additional commands to work with files
Oops! When things go wrong
3. Pantry usage tips
Use your shell
History features
Aliases and functions
Variables and arrays
Short options and abbreviations
Files and collections
Using traits
4. Creating new foods, and changing the nutrients and available units of existing foods
Create the food and its traits
Add available units
Create nutrients
Check your work
The addFoods script
Commands to edit the nutrients and available units of foods
5. Creating recipes
Create the recipe and its traits
Add ingredients
Add available units
Seeing your new recipe
The addRecipes script
Editing recipes
A. Pantry limitations
No multibyte or locale awareness
High RAM usage
Only one file at a time may be open
Size of collections, number of collections, number of nutrients, etc.
Numbers are approximations
B. How the USDA National Nutrient Database for Standard Reference became the starter_database file
C. Reference pages
pantry — nutrient tracking and analysis
pantryd — nutrient tracking and analysis server

List of Examples

2.1. Starting the Pantry server
2.2. Opening a database
2.3. Getting server status
2.4. The name report
2.5. The info report
2.6. The blank report
2.7. The groups report
2.8. Using --search name
2.9. Using multiple --search options
2.10. Using the group trait in a search
2.11. The --ignore-case option
2.12. Patterns, anchors, and --exact-match
2.13. Changing traits
2.14. Changes only affect foods in the buffer
2.15. Changing the quantity trait
2.16. Units report
2.17. Changing the unit trait
2.18. Papaya units reports
2.19. Adding foods to a collection
2.20. Using the --edit option
2.21. Using the --delete option
2.22. The goals report
2.23. My fruititarian foods
2.24. My fruititarian report
2.25. The nuts report
2.26. Using the Goals and Nuts reports
2.27. A basic sorting example
2.28. Sorting in descending order
2.29. Specifying more than one --key
2.30. Using the --list option to sort foods
2.31. Using the --auto-order option
2.32. Using the --refuse option
2.33. Using the --by-nut option
2.34. The paste report
2.35. Seeing if there are unsaved changes
2.36. Using the --save-as option
4.1. Creating a new food
4.2. Adding an available unit
4.3. Adding nutrients
4.4. Seeing the new food
4.5. Using --rename-nut
4.6. Using --rename-avail-unit
4.7. Using --delete-nuts
4.8. Using --delete-avail-units
5.1. Creating a recipe
5.2. Adding ingredients to a single collection
5.3. Add ingredients to the food
5.4. The recipe report

About Pantry

Pantry is a command-line oriented nutrient analysis program. It can help you find the nutrient content of foods and recipes. You can also use it to track and analyze your nutrient intake.

Pantry is a true command-line oriented program. There are no menus or prompts. Of course this is clearly different from Web-based or GUI programs, but it also differs from programs that run in a text console but are menu-driven (such programs have been called text user interface programs).

Pantry may or may not be what you are looking for, so here is a rundown of the advantages and disadvantages of this program.

Pantry's advantages

Pantry's true command-line interface gives it many advantages. Because Pantry works from your shell prompt, you can easily combine it with other text-processing tools. You can also easily write scripts incorporating Pantry, in ways that even I cannot anticipate. This is the strength of the Unix "toolbox" way of using a computer.

In addition, nothing beats the speed of a command-line program for something you use frequently and are familiar with. If you are using a nutrient-analysis program to track your daily food intake, you will appreciate how quickly you can use Pantry for this purpose. Indeed, I developed Pantry due to my frustration with current tools because it was very tedious to use them to quickly tally a day's food intake.

Because Pantry runs from a text console, you can easily set it up on one computer that has an SSH server running. You may then access your nutrient data from any computer that has an SSH client. Though Web-based nutrition-tracking services also offer the ability to access your data from any Internet-connected computer, Pantry is more private than Web-based services.

Pantry's disadvantages

The biggest disadvantage of using Pantry is the same as its biggest advantage: its command-line interface. Graphical user interface programs attempt to be self-documenting: just sit down, click on some buttons, and hopefully you can figure things out. With Pantry, on the other hand, you will absolutely have to read this manual to figure out how it works, and you will need some practice before you are comfortable with Pantry. In this way, Pantry resembles other command-line oriented Unix programs. As with other Unix programs, once you learn Pantry, you will love its speed and efficiency--but you will have to spend some time learning.

Similarly, because of its command-line interface, you will find that you are most efficient with Pantry if you know your way around a Unix shell prompt. For example, you will find that you can use Pantry more quickly if you know how to use your shell's features to manipulate your command history. Such knowledge is useful for any Unix command-line program, not just Pantry; however, building up this knowledge takes some time.

Pantry has no tools to graphically visualize your food intake. I might eventually add such features using Gnuplot or something similar.

Alternatives

I know I like to check out many possible programs before settling on one to learn to use--and I always like trying new programs too. Here are some possible alternatives to Pantry that you might take a look at:

NUT

This is probably the leading nutrient analysis program for Unix. It has a text user interface and is very mature. NUT website.

Crosstrainer

The best GUI program for nutrient analysis that I have ever seen. It does more than nutrient analysis, too--for example it can track your exercise too. (Pantry will never do anything other than nutrients.) Crosstrainer only runs on Windows though, and I have not used Windows in quite awhile. Crosstrainer is also somewhat expensive. Crosstrainer website.

nutritiondata.com

This website has great tools, and neat graphical features. Using it as a food diary is somewhat cumbersome, however. nutritiondata.com website.

Fitday

This is the best food diary website that I have found. Fitday website.

Pantry on the Internet

Visit the Pantry home page at http://www.smileystation.com/pantry. I post new versions there. I also update the Pantry Freshmeat listing at http://www.freshmeat.net/projects/pantry when I release new versions. Freshmeat has subscription services that will notify you when there is a new release.

Pantry's source code is tracked with Git; you can clone the repository from Github.

About the documentation

Right now you are reading the Pantry User Guide. This is a narrative document to teach you step by step how to use Pantry. I hope you'll read it from beginning to end. In the PDF version, some of the examples run off the right side of the page. If you're curious about what you're missing (typically very little of substance) just look at the HTML version.

Also, like any good[1] Unix program, Pantry has manual pages. They are available by invoking "man pantry" or "man pantryd" at the command prompt. The manual pages are not intended to teach you how to use Pantry. Instead, they serve as reference guides if you wish to jog your memory about how a particular feature works. You will also find the manual pages at the end of this User Guide.



[1] I don't mean to presume that Pantry is a good program, but I have tried to imitate the best where I can.

Installation

Pantry is written in C++ and distributed using the GNU Autotools. If you know what that previous sentence means, then you don't need to read the rest of this section--install Pantry the usual way.

If on the other hand you have never compiled software, never fear. Sometimes compiling software from source code can be tricky, but Pantry is quite easy to compile and install. This section will lead you through the process step by step.

Pantry should compile and run perfectly on any recent Unix-like operating system. This includes any Linux system, the BSDs, Mac OS X, and any of the proprietary Unices. It might also compile and run in Cygwin; I am unfamiliar with Cygwin so I can't offer any help there. Pantry will not compile or run in Microsoft Windows, and I doubt this will ever change.

Install everything you will need to compile Pantry

You'll need to have the following software installed before you attempt to compile Pantry. All this software is quite common and will be readily available on any Unix system. On a Linux system, use your distribution's package management system to install this software, if it is not installed already.

make

make invokes the compiler, and it also installs the compiled binaries (and other files) in their proper locations. On Linux this package is typically named make.

The standard C library

The standard C library contains a variety of essential routines that Pantry uses for file operations and interprocess communications. I can guarantee that the standard C library is already installed on your system, as no Unix system can work without one. However, on many Linux distributions you will need to install the additional "development" files. These files are necessary if you wish to compile software from source. Look for a package named libc6-dev or glibc-devel or something similar. Most other Unix systems will already have these additional files installed.

A C++ compiler

Pantry is written in C++ so you will need a C++ compiler. Pantry uses only standard features of the C++ language, so any recent C++ compiler will work. On Linux, install the GNU C++ compiler. Look for a package named g++, gcc-g++, or something similar.

C++ standard library

All C++ programs require the standard C++ library. Though the standard C++ library likely is already installed on your system, you may need to install the additional "development" files, especially if you are on Linux. Look for a package named libstdc++-devel, libstdc++-dev, or something similar.

Compiling and installing

Now that you've installed all the prerequisites, compiling and installing Pantry is simple:

  1. In your normal user account, unpack the tarball with bunzip2 < pantry-32.tar.bz2 | tar x

  2. Change to the newly created directory with cd pantry-32.

  3. Run ./configure.

  4. Run make.

  5. Become the root user by issuing su or sudo -i.

  6. Install Pantry with make install.

If you are curious about what the commands listed above are doing, consult one of these tutorials about how to install software from source code:

Getting help and reporting bugs

The best place to start when you're learning Pantry is this user guide, which was written to teach you everything you need to know. The manual pages, pantry(1) and pantryd(1) were not intended to teach you how to use Pantry; they're better for jogging your memory on how to use this feature or that.

If you're having trouble installing or using Pantry, send me an email at omari@smileystation.com. Also, please send me an email if you have any suggestions for improvement or have any bugs to report.

Chapter 1. The Pantry Paradigm

Every software package comes with a set of terminology and ideas that you need to learn in order to use the software most effectively. For example, emacs users are familiar with buffers, regions, and the kill ring. vi users know the difference between normal mode and insert mode. Web browser users know about URLs (or, at least, addresses) and links. Pantry is no different, as it comes with its own set of terminology and its own paradigm, as you will learn about in this chapter.

A client-server model

Pantry is designed to work entirely from the command line. This gives you full access to the power of your shell as you work with Pantry. However, Pantry needs to deal with lots of data. It would take too long to load all this data into memory every time you execute a Pantry command.

The solution is a client-server model. When you use Pantry, you'll start a server which runs in the background. This server will hold all the data you're working with. To interact with the server from the command line, you'll use a client program. When you're done with the server, you can shut it down--or you can just leave it running. It's up to you.

Pantry comes with two binary programs, with pantryd being the server and pantry being the client. Generally you will only run one server at a time. The server and client communicate with each other using a UNIX domain socket, which is a common means of interprocess communication on Unix. By default, this socket is a file at $HOME/.pantrySocket. If you want to use a different location for your socket file, you can do so by setting the environment variable PANTRY_SOCKET before you start pantryd, and you will also need to be sure the PANTRY_SOCKET variable is set each time you run pantry. Specify the entire path to the socket, including the filename itself (it need not be named .pantrySocket). By using the PANTRY_SOCKET variable, you can run more than one pantryd server simultaneously.[2]

Foods

You will work with Pantry by manipulating what we will call foods. Each food in Pantry has various pieces of data associated with it, called traits, nutrients, and available units.

Traits

A food's traits is a set of twelve strings. Each of these strings indicates something interesting about the food. For instance, four of these traits are name, date, quantity, and unit. For a particular food, these might be equal to Apples, raw, with skin, Wednesday (to indicate the date that you ate it) 2 and large (3-1/4" dia) to indicate that you ate two large apples. Of course you can change a food's traits. For instance, you can rename any food whenever you want, and you can change its quantity and unit traits to indicate how much you ate (or just to see the nutrient breakdown for that particular quantity and unit.)

Twelve food traits

name

This is the name of the food, such as Apples, raw, with skin.

group

You can assign whatever you like to this trait to group foods. The foods in the starter_database file already have group traits corresponding to the food groups used by USDA; for instance, Apples, raw, with skin has a group trait of Fruits and Fruit Juices.

quantity

This is a number. You can use an integer, like 2; a decimal, like 2.5; a fraction, like 1/2; or a mixed number, like 2 1/2.

unit

This is a string. It must be equal to one of the food's available units. Every food has g, oz, and lb as available units; you can also assign additional available units to a food, as we will discuss later. Later we will also see how you can find out what a food's available units are.

date

You can assign whatever you wish to this trait to indicate when you ate a food, if you wish. This does not need to be formatted any particular way, so you can use 2008-05-18, Sunday, or the day before yesterday if you want.

meal

A string indicating what meal you ate a food at, such as Lunch or midday snack.

comment

Any comments you may wish to add.

order

Sometimes you may want your foods to be sorted in a particular order when you print reports; to do that you can assign appropriate values to this trait, such as a for one food and b for the next food. As we will see later, Pantry can also assign values to this trait for you if you wish.

refuse

A description of the refuse of a food--that is, the part you don't eat, like bones or shells. For Apples, raw, with skin, this is Core and stem.

percent-refuse

The percent of the food that is refuse. As we will see later Pantry can use the value of this trait to make it easier for you to keep track of food quantities. As with the quantity trait, this can be an integer, decimal value, fraction, or mixed number. For Apples, raw, with skin, this is 10, which is roughly the percentage of an apple's weight that is core and stem.

yield

Later you will learn how to create your own recipes in Pantry. This trait indicates the total yield of a recipe, in grams.

instructions

For a recipe, this may contain any preparation instructions you may wish to add.

Nutrients

A food's nutrients is a set of pairs of strings and numbers. These indicate the nutrient breakdown of a food. For example, the food with the name trait Apples, raw, with skin whose quantity trait is 1 and whose unit trait is large (3-1/4" dia) has 100 nutrients total. Some of the more interesting ones are Calories which is 116; Calcium, mg which is 13, and Dietary Fiber, g which is 5. A food's nutrients adjust automatically as you change its quantity or unit traits.

Available units

A food's available units indicate various possible quantities of a food, and how much each given quantity weighs in grams. For example, the food whose name trait is Apples, raw, with skin has ten available units total. Among these are large (3 1/4" dia), which is 223g, and cup slices, which is 109g. Every food always has g, oz, and lb as available units.

Collections and databases

A collection holds foods. Every food must be in a collection. You can use collections to group foods in a way that is convenient to you--for example, by day of the week, or by foods you eat frequently. A database holds one or more collections. In Pantry you can only work with one database at a time, though you can work with more than one collection as long as they are in the same database. You can save databases to disk so you can load them again later.



[2] You might need to use PANTRY_SOCKET if the default socket location does not work for you because, for example, you don't have permission to create files in your home directory or if your home directory is on a filesystem that does not allow creation of sockets. Otherwise, I can't imagine why most folks would want to run more than one server simultaneously, though this feature does come in handy when I am testing new versions of Pantry and preparing them for release.

Chapter 2. Manipulating foods

Now that you know some essential Pantry terminology, you're ready to jump in and do something interesting. In this chapter you'll learn how to use Pantry to find nutrition information about foods.

Opening files and getting server status

As you learned in the previous chapter, Pantry employs a client-server architecture. So the first thing you must do when working with Pantry is start a server. To start a server, simply type pantryd at a command prompt:

Example 2.1. Starting the Pantry server

$ pantryd 

This starts up a Pantry server in the background and returns you to your prompt. This server will keep running, even after you logout of the shell from which you started the server.[3] If you're a skeptic and you don't believe that you actually have a program running in the background, you can verify that a Pantry server is running by using your ps command.

Now to interact with the server you'll use the pantry command. First let's load a database. Pantry comes with the starter_database file. It contains over 7,000 foods from the USDA's National Nutrient Database for Standard Reference. You'll find this file at $PREFIX/share/pantry/data/starter_database, where $PREFIX is the prefix you used when you ran the configure script. (This defaults to /usr/local.) So to open the file run a command similar to this. Just make an appropriate substitution for the location of your starter_database file:

Example 2.2. Opening a database

$ pantry --open data/starter_database 

As with the previous command, you're returned to your prompt without a message. Pantry generally is quite terse--if it has nothing surprising to say, or if you have not asked it to say anything, then it stays quiet. If you're wondering if that last command really did anything, you can ask the server to report its status:

Example 2.3. Getting server status

$ pantry --status 
Current filename: /home/massysett/pantry-git/data/starter_database
Collections: 
  7413 master 

This shows that the database you just opened has a single collection, called master, with 7413 foods.

The name, info, and blank reports

Next let's learn how to print reports, which are Pantry's way of telling you what you want to know about foods. Most invocations of the Pantry command take the form pantry [options] COLLECTION... When you enter a pantry command, you will usually specify one or more collections as non-option arguments[4]. For example, as we saw above, the starter_database file comes with one collection, named master.

In order to learn exactly what foods are in the master collection, you can print reports about the foods. For example, the simplest report is the name report, which prints the name trait of every food in the buffer:

Example 2.4. The name report

$ pantry --print name master | head 
Croissants, apple
Beef, ground, patties, frozen, cooked, broiled
Rice, white, glutinous, cooked
McDONALD'S, McFLURRY with OREO cookies
Crackers, wheat, regular
Onions, sweet, raw
Fast foods, chicken fillet sandwich, with cheese
Alcoholic beverage, wine, cooking
Lamb, New Zealand, imported, frozen, composite of trimmed retail cuts, separable lean and fat, raw
Bread, french or vienna (includes sourdough)

Thus you use the --print option to print reports. The --print option takes a single argument, which is the name of the report--here, name. Finally you specify the collection or collections that has the foods you're interested in--here, master. Pantry first copies every food from the master collection into the buffer. It then prints a name report for every one of those foods. That's a lot of foods--over 7,000 of them, so in the manual I've piped the output to head to save some space. After your pantry command is done, the foods that were copied to the buffer are gone, and the foods in the master collection are unchanged.

To know more than just the name of a food, use the info report. It prints information about most of a food's traits. It does not print information about the food's name trait (for that, use the name report) or about some of the traits that are related only to foods that are recipes (we'll discuss reports applicable to recipes later.) To save space, the info report does not print information about a trait if it is blank. You can print more than one report at a time simply by specifying multiple --print options.

Example 2.5. The info report

$ pantry --print name --print info master | head 
Croissants, apple
100 g (100g)
Group: Baked Products
Beef, ground, patties, frozen, cooked, broiled
100 g (100g)
Group: Beef Products
Rice, white, glutinous, cooked
100 g (100g)
Group: Cereal Grains and Pasta
McDONALD'S, McFLURRY with OREO cookies

For every food in the buffer, Pantry first printed a name report and then printed an info report. As you can see, some whitespace would help make this more readable. To get whitespace use the blank report, which prints a blank line:

Example 2.6. The blank report

$ pantry --print name --print info \
--print blank master | head 
Croissants, apple
100 g (100g)
Group: Baked Products

Beef, ground, patties, frozen, cooked, broiled
100 g (100g)
Group: Beef Products

Rice, white, glutinous, cooked
100 g (100g)

All the reports we have seen so far are printed once for every food in the buffer. We'll call these reports food reports. On the other hand, some reports are printed just once for the entire buffer, no matter how many foods are in the buffer. We'll call these reports summary reports because they summarize information for the entire buffer. One summary report is the groups report, which tells you information about the group trait of every food in the buffer:

Example 2.7. The groups report

$ pantry --print groups master 
Group name                                        Food count
------------------------------------------------------------
Baby Foods                                        314       
Baked Products                                    489       
Beef Products                                     485       
Beverages                                         262       
Breakfast Cereals                                 440       
Cereal Grains and Pasta                           180       
Dairy and Egg Products                            222       
Ethnic Foods                                      153       
Fast Foods                                        354       
Fats and Oils                                     220       
Finfish and Shellfish Products                    255       
Fruits and Fruit Juices                           321       
Lamb, Veal, and Game Products                     345       
Legumes and Legume Products                       359       
Meals, Entrees, and Sidedishes                    123       
Nut and Seed Products                             128       
Pork Products                                     319       
Poultry Products                                  371       
Sausages and Luncheon Meats                       233       
Snacks                                            139       
Soups, Sauces, and Gravies                        497       
Spices and Herbs                                  61        
Sweets                                            338       
Vegetables and Vegetable Products                 805       
------------------------------------------------------------
  Total                                           7413      

Selecting foods with the --search option

As you learned in the previous section, the information in your reports in Pantry depends on what foods are in the buffer, and when you specify a collection name as an argument to the pantry command, Pantry copies all the foods from that collection into the buffer. So every report we saw in the previous section pertained to all the foods in the master collection in the starter_database file--that's over 7,000 foods. Often you'll only be interested in a fraction of the foods in a particular collection. That's where the --search option comes in.

With the --search option, you specify a particular trait, such as name, date, or group, and a pattern you wish to match for that particular trait. As we learned before, Pantry first copies every food from the each collection you specify into the buffer. However, when you specify --search options, Pantry then eliminates every food whose trait does not match the pattern you specified. An example will help:

Example 2.8. Using --search name

$ pantry --search name "Apples, raw, with skin" \
--print name --print info master 
Apples, raw, with skin
100 g (100g)
Group: Fruits and Fruit Juices
Refuse: 10 percent Core and stem

You have to quote the second argument to the --search option if, as here, it contains characters that the shell gives special meaning to, such as spaces. Here is an excellent guide that explains why and when quoting is necessary.

As with the --print option, you may specify multiple --search options in a single command. The effect of multiple --search options is cumulative; that is, a food must match all of the --search options specified, or Pantry will remove it from the buffer.

Example 2.9. Using multiple --search options

$ pantry --search name Apples --print name master 
Apples, dried, sulfured, stewed, without added sugar
Apples, dried, sulfured, uncooked
Applesauce, canned, sweetened, with salt
Apples, canned, sweetened, sliced, drained, heated
Apples, raw, without skin, cooked, microwave
Apples, frozen, unsweetened, unheated
Apples, dried, sulfured, stewed, with added sugar
Apples, dehydrated (low moisture), sulfured, stewed
Applesauce, canned, unsweetened, with added ascorbic acid
Apples, raw, with skin
Applesauce, canned, unsweetened, without added ascorbic acid (includes USDA commodity)
Apples, raw, without skin
Apples, dehydrated (low moisture), sulfured, uncooked
Apples, canned, sweetened, sliced, drained, unheated
Apples, frozen, unsweetened, heated
Apples, raw, without skin, cooked, boiled
Applesauce, canned, sweetened, without salt (includes USDA commodity)
$ pantry --search name Apples \
--search name skin --print name master 
Apples, raw, without skin, cooked, boiled
Apples, raw, without skin
Apples, raw, with skin
Apples, raw, without skin, cooked, microwave

You can search using any trait you wish, not just the name trait. For example, you can show all foods with the word Fruit in their group trait:

Example 2.10. Using the group trait in a search

$ pantry --search group Fruit --print name \
--print info --print blank master | head 
Strawberries, canned, heavy syrup pack, solids and liquids
100 g (100g)
Group: Fruits and Fruit Juices

Pineapple, canned, water pack, solids and liquids
100 g (100g)
Group: Fruits and Fruit Juices

Prunes, dehydrated (low-moisture), uncooked
100 g (100g)

As with many things Unix, by default the --search option is case sensitive. To make it case insensitive, use the --ignore-case option. This makes the pattern to every --search option case insensitive.

Example 2.11. The --ignore-case option

$ pantry --search name papaya \
--print name master 
Babyfood, fruit, guava and papaya with tapioca, strained
Babyfood, fruit, papaya and applesauce with tapioca, strained
Fruit salad, (pineapple and papaya and banana and guava), tropical, canned, heavy syrup, solids and liquids
$ pantry --ignore-case \
--search name papaya \
--print name master 
Babyfood, fruit, guava and papaya with tapioca, strained
Babyfood, fruit, papaya and applesauce with tapioca, strained
Papaya nectar, canned
Fruit salad, (pineapple and papaya and banana and guava), tropical, canned, heavy syrup, solids and liquids
Papayas, raw

Also, by default the search patterns are regular expressions.[5] If a regular expression matches any part of the trait, then the food matches. This can have mildly unexpected results. Sometimes you may wish to use anchors. In addition, there is an --exact-match option which turns off regular expressions. When you use exact match, all search patterns must exactly match the search patterns given.

Example 2.12. Patterns, anchors, and --exact-match

$ pantry --search name "Apples, raw, without skin" \
--print name master 
Apples, raw, without skin, cooked, boiled
Apples, raw, without skin
Apples, raw, without skin, cooked, microwave
$ pantry --search name "Apples, raw, without skin$" \
--print name master 
Apples, raw, without skin
$ pantry --exact-match \
--search name "Apples, raw, without skin" \
--print name master 
Apples, raw, without skin

The units report, and changing foods

Now you know how to search for foods and print information about them. This is often useful all by itself, but often you will want to change foods. To change a trait, just use the --change option:

Example 2.13. Changing traits

$ pantry --ignore-case --search name papaya \
--change group "Tropical Fruits" \
--print name --print info --print blank \
master 
Babyfood, fruit, guava and papaya with tapioca, strained
100 g (100g)
Group: Tropical Fruits

Babyfood, fruit, papaya and applesauce with tapioca, strained
100 g (100g)
Group: Tropical Fruits

Papaya nectar, canned
100 g (100g)
Group: Tropical Fruits

Fruit salad, (pineapple and papaya and banana and guava), tropical, canned, heavy syrup, solids and liquids
100 g (100g)
Group: Tropical Fruits

Papayas, raw
100 g (100g)
Group: Tropical Fruits
Refuse: 33 percent Seeds and skin


As you already know, when you execute a pantry command, Pantry first copies all foods from every collection you specify into a buffer. Pantry then removes from the buffer all foods that do not match any --search optionis you specified. Next is where the --change option comes in. Pantry changes every food in the buffer using any --change options you have specified. After that, Pantry prints any reports you have requested with the --print option.

Remember that Pantry first copies foods from the collections into the buffer, so when you use the change option, the original foods that are in the collection are not changed. In the last example we changed the group trait of some foods that have papaya in their name trait, but as this shows, this change did not affect the foods in the master collection:

Example 2.14. Changes only affect foods in the buffer

$ pantry --ignore-case --search name papaya \
--print name --print info --print blank \
master 
Babyfood, fruit, guava and papaya with tapioca, strained
100 g (100g)
Group: Baby Foods

Babyfood, fruit, papaya and applesauce with tapioca, strained
100 g (100g)
Group: Baby Foods

Papaya nectar, canned
100 g (100g)
Group: Fruits and Fruit Juices

Fruit salad, (pineapple and papaya and banana and guava), tropical, canned, heavy syrup, solids and liquids
100 g (100g)
Group: Fruits and Fruit Juices

Papayas, raw
100 g (100g)
Group: Fruits and Fruit Juices
Refuse: 33 percent Seeds and skin


To make changes permanent, you can use the --add, --edit, and --delete options, which we will talk about later.

As we discussed earlier, every food in Pantry has twelve traits. Of these twelve, you can assign whatever text you want to eight: name, group, date, meal, comment, order, and refuse. Of course you might be less confused if you, say, refrain from using the refuse trait to store information about when you ate a food, but that is up to you. You are not constrained to using a particular format for the date trait; later on, when we discuss the --key option, we'll learn of some considerations you might want to take into account when assigning information to this trait.

The quantity trait is a number. When you assign values to it using the --change option, you must use a value that evaluates to a number. You can use whole numbers (such as 2), decimals (such as 2.5), fractions (such as 2/3) or mixed numbers (such as 1 2/3). If you try to use anything else for the quantity trait, Pantry will give you an error message and quit.

Example 2.15. Changing the quantity trait

$ pantry --search name "Apples, raw, with skin" \
--change quantity "2 1/2" \
--print name --print info master 
Apples, raw, with skin
2 1/2 g (2.5g)
Group: Fruits and Fruit Juices
Refuse: 10 percent Core and stem

Entering 0 for a food's quantity trait does not delete a food; to do that, use the --delete option which we will talk about later.

The percent-refuse trait is similar to the quantity trait in that it is also a number. However, the percent-refuse trait has one additional requirement: it must be between 0 and 100, inclusive, because a food can't have less than zero percent refuse or more than 100 percent refuse.

As we discussed much earlier, each food in Pantry may have a number of available units. Knowing what these are will come in handy later when you wish to change the units of a food, but for now let's just see what a units report looks like.

Example 2.16. Units report

$ pantry --ignore-case --search name papaya \
--print name --print units --print blank \
master 
Babyfood, fruit, guava and papaya with tapioca, strained
   jar (113g)

Babyfood, fruit, papaya and applesauce with tapioca, strained
   jar (113g)

Papaya nectar, canned
   cup (250g)
   fl oz (31g)

Fruit salad, (pineapple and papaya and banana and guava), tropical, canned, heavy syrup, solids and liquids
   cup (257g)

Papayas, raw
   cup, cubes (140g)
   cup, mashed (230g)
   large (5-3/4" long x 3-1/4" dia) (380g)
   medium (5-1/8" long x 3" dia) (304g)
   small (4-1/2" long x 2-3/4" dia) (152g)


Every food has g, oz, and lb available as units, so the units report does not show these to save some space.

The unit trait must be set to be equal to one of the food's available units. When you are changing a food's unit, the second argument to the --change option is a regular expression that must match exactly one of the food's available units. If the regular expression does not match exactly one of the food's available units, Pantry will give you an error message and quit.

Example 2.17. Changing the unit trait

$ pantry --search name "Papayas, raw" \
--change quantity 1 \
--change unit large \
--print name --print info master 
Papayas, raw
1 large (5-3/4" long x 3-1/4" dia) (380g)
Group: Fruits and Fruit Juices
Refuse: 33 percent Seeds and skin

As always with the --change options, using --change unit will change every food in the buffer so that its unit matches the pattern you give. For example, take the following output from a units report:

Example 2.18. Papaya units reports

$ pantry --ignore-case --search name papaya \
--print name --print units --print blank \
master 
Babyfood, fruit, guava and papaya with tapioca, strained
   jar (113g)

Babyfood, fruit, papaya and applesauce with tapioca, strained
   jar (113g)

Papaya nectar, canned
   cup (250g)
   fl oz (31g)

Fruit salad, (pineapple and papaya and banana and guava), tropical, canned, heavy syrup, solids and liquids
   cup (257g)

Papayas, raw
   cup, cubes (140g)
   cup, mashed (230g)
   large (5-3/4" long x 3-1/4" dia) (380g)
   medium (5-1/8" long x 3" dia) (304g)
   small (4-1/2" long x 2-3/4" dia) (152g)


Remember that every food has g, oz, and lb as available units, so I could have appended --change unit "lb" to the previous command. However, had I appended --change unit small to the previous command, pantry would have given me an error message and quit because only one of the foods in the buffer had an available unit that matched that pattern.

Let's say I want to change a papaya's unit to g (for grams). What if I wanted to run pantry --search name "Papayas, raw" --change unit g master? That would give me an error message because g matches both g and large (5-3/4" long x 3-1/4" dia). One solution to this is to use anchors by specifying --change unit '^g$' instead.[6] Another is to use the --exact-match option. Because the second argument to the --change unit option is a regular expression, it respects the --exact-match and --ignore-case options just as the --search option does. Thus, pantry --exact-match --search name "Papayas, raw" --change unit g master works perfectly.

Making changes permanent

As we've been pointing out, when you make changes to foods using the --change option, these changes are not permanent. This is because those changes are to foods that are in the buffer, which is Pantry's temporary holding place for foods. You get a new buffer every time you run a pantry command.

There are three ways to make your changes permanent. The one you'll use the most is the --add option. This takes the entire buffer and adds its contents to the specified collection:

Example 2.19. Adding foods to a collection

$ pantry --search name "Apples, raw, with skin" \
--change quantity 2 \
--change unit medium \
--change date 2008-06-22 \
--change meal Lunch \
--add diary \
master 
$ pantry --print name --print info diary 
Apples, raw, with skin
2 medium (3" dia) (364g)
Group: Fruits and Fruit Juices
Date: 2008-06-22
Meal: Lunch
Refuse: 10 percent Core and stem

The --add option is the easiest way to keep a food diary. You simply search for foods in the master collection, change their traits as appropriate (such as their quantity, date, and meal traits) and then add them to another collection. I typically add all my diary foods to one collection, diary, but you can use multiple collections for this purpose--such as one collection for each day, week, or whatever. You can even add a food to more than one collection at a time; just use multiple --add options, one for each collection.

Once you have added a food to a collection with --add, that food is independent of the collection it came from. That is, in the previous example, if you then make changes to the apple you just added to diary, this will not affect the food in the master collection.

Thus the --add option works by copying foods from the buffer into a collection. Sometimes though you will want to change a food that is already in a collection, without copying it. For example, let's say that in the previous example I made a mistake. I really wanted to indicate that I ate one medium apple, not two. The --edit option will help you here.

Example 2.20. Using the --edit option

$ pantry --search name "Apples, raw, with skin" \
--search date 2008-06-22 \
--search meal Lunch \
--change quantity 1 \
--edit \
diary 
$ pantry --search date 2008-06-22 \
--print name --print info --print blank \
diary 
Apples, raw, with skin
1 medium (3" dia) (182g)
Group: Fruits and Fruit Juices
Date: 2008-06-22
Meal: Lunch
Refuse: 10 percent Core and stem


With the --edit option, Pantry copies foods from the source collections and makes the changes indicated using the --change option, as it always does. However, when you use --edit, Pantry will make changes to the foods that are inside the original collections, as well as making changes to the foods that are in the buffer.

Or, let's say that I decided that I didn't really eat an apple after all. Then I can use the --delete option:

Example 2.21. Using the --delete option

$ pantry --search date 2008-06-22 \
--search name Apples \
--print name \
--delete diary 
Apples, raw, with skin
$ pantry --status 
Current filename: /home/massysett/pantry-git/data/starter_database
Collections: 
     0 diary (changed)
  7413 master 

As you can see, the diary collection now has no foods because you deleted the single food that was in the collection.

With the --delete, option, after copying foods into the buffer and making any changes you specify, Pantry then deletes the foods from the original collections. The foods are still present in the buffer, which is why you can still --print them.

Reports about nutrients

There are two reports to tell you about the nutrient content of foods. First we will discuss the goals report. It allows you to specify the nutrients you wish to see in a report:

Example 2.22. The goals report

$ pantry --search name "Apples, raw, with skin" \
--print name --print info --print goals \
--goal Calories 2600 \
--goal "Total Fat, g" 43 \
--goal "Protein, g" 162 \
--goal "Total Carbohydrate, g" 390 \
--goal "Dietary Fiber, g" 0 \
master 
Apples, raw, with skin
100 g (100g)
Group: Fruits and Fruit Juices
Refuse: 10 percent Core and stem
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                52     2     100   
Total Fat, g                            0      0     100   
Protein, g                              0      0     100   
Total Carbohydrate, g                   14     4     100   
Dietary Fiber, g                        2            100   

As the example illustrates, you specify the nutrients you wish to see in the goals report by using multiple --goal options, and the nutrients are shown in the order in which you asked for them with the --goal options. The first argument to each --goal option specifies the nutrient you wish to see. Unlike many other things in Pantry, this argument is not a regular expression--instead, for a nutrient to be printed in the goals report, its name must exactly match one of the nutrients specified with a --goal option. The --goal option is always case sensitive, even if you have specified the --ignore-case option.

The second argument to each --goal option is a goal. For instance, here I have specified that it is my goal to eat 2600 calories, 43 grams of fat, and so on. These goals can be per day, per month, per meal...whatever you want. If you don't have a goal for a particular nutrient, just specify 0. (You do, however, have to specify a goal, even if it is zero.)

With that, you can probably figure out what all the columns in the goals report mean. The first is simply the name of the nutrient. The second is the amount of the nutrient present. The third column is the ratio of the second column to the goal you specified, expressed as a percentage.

The fourth column shows this nutrient's percentage of the total amount of that nutrient in the buffer. This makes more sense with an example. Suppose I am a fruititarian:

Example 2.23. My fruititarian foods

$ pantry --search name 'Apples, raw, with skin' \
--change quantity 3 \
--change unit large \
--change date 2008-06-12 \
--change meal Breakfast \
--add diary \
master 
$ pantry --search name 'Bananas, raw' \
--change quantity 1 \
--change unit medium \
--change date 2008-06-12 \
--change meal Lunch \
--add diary \
master 
$ pantry --search name 'Papayas, raw' \
--change quantity 2 \
--change unit large \
--change date 2008-06-12 \
--change meal Dinner \
--add diary \
master 

Example 2.24. My fruititarian report

$ pantry --search date 2008-06-12 \
--print name --print info --print goals \
--print blank \
--goal Calories 2600 \
--goal "Total Fat, g" 43 \
--goal "Protein, g" 162 \
--goal "Total Carbohydrate, g" 390 \
--goal "Dietary Fiber, g" 0 \
diary 
Apples, raw, with skin
3 large (3-1/4" dia) (669g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Breakfast
Refuse: 10 percent Core and stem
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                348    13    46    
Total Fat, g                            1      3     44    
Protein, g                              2      1     23    
Total Carbohydrate, g                   92     24    48    
Dietary Fiber, g                        16           49    

Bananas, raw
1 medium (7" to 7-7/8" long) (118g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Lunch
Refuse: 36 percent Skin
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                105    4     14    
Total Fat, g                            0      1     15    
Protein, g                              1      1     17    
Total Carbohydrate, g                   27     7     14    
Dietary Fiber, g                        3            9     

Papayas, raw
2 large (5-3/4" long x 3-1/4" dia) (760g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Dinner
Refuse: 33 percent Seeds and skin
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                296    11    40    
Total Fat, g                            1      2     41    
Protein, g                              5      3     61    
Total Carbohydrate, g                   75     19    38    
Dietary Fiber, g                        14           42    


The goals report tells you only about the nutrients that you ask for. To know about all the nutrients in a food, use the nuts report instead. Because the people at USDA are so industrious, the foods in the starter_database file have lots of nutrients. Let's see some of them for the apple. Of course when you run this on your computer you can omit the | head, but I did that here to save some space in the manual. The columns in the nuts report mean the same as the corresponding columns in the goals report; however, unlike the goals report, you do not need to enter a goal for a nutrient in order for the nutrient to be shown in the nuts report; instead, all of a food's nutrients are shown.

Example 2.25. The nuts report

$ pantry --search name "Apples, raw, with skin" \
--print name --print nuts master | head 
Apples, raw, with skin
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
10:0, g                                 0                  
12:0, g                                 0                  
14:0, g                                 0            100   
16:0, g                                 0            100   
16:1 undifferentiated, g                0                  
18:0, g                                 0            100   
18:1 undifferentiated, g                0            100   

The --goals and --nuts report tell you about each food in the buffer. To get information about the total nutrient content of a buffer, use the Goals and Nuts summary reports.

Example 2.26. Using the Goals and Nuts reports

$ pantry --search date 2008-06-12 \
--print Goals \
--goal Calories 2600 \
--goal "Total Fat, g" 43 \
--goal "Protein, g" 162 \
--goal "Total Carbohydrate, g" 390 \
--goal "Dietary Fiber, g" 0 \
diary 
Sum of nutrients with a goal:
Nutrient name                           Amount %G    
-----------------------------------------------------
Calories                                749    29    
Total Fat, g                            3      6     
Protein, g                              8      5     
Total Carbohydrate, g                   194    50    
Dietary Fiber, g                        33     
$ pantry --search date 2008-06-12 \
--print Nuts diary | head 
Sum of all nutrients:
Nutrient name                           Amount %G    
-----------------------------------------------------
10:0, g                                 0            
12:0, g                                 0            
14:0, g                                 0            
16:0, g                                 1            
16:1 undifferentiated, g                0            
18:0, g                                 0            
18:1 undifferentiated, g                0            

Sorting reports, and using --auto-order

For all practical purposes, Pantry stores foods in collections in no particular order. Thus, when you use the --print option to print reports, you don't know what order your foods will come out in. That can make it hard to find the information you're looking for.

That's why Pantry has options so it will sort foods in an order you specify. You sort foods by adding keys. A key is a particular trait that you wish to use to sort foods. For example:

Example 2.27. A basic sorting example

$ pantry --key name \
--print name --print info --print blank \
diary 
Apples, raw, with skin
3 large (3-1/4" dia) (669g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Breakfast
Refuse: 10 percent Core and stem

Bananas, raw
1 medium (7" to 7-7/8" long) (118g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Lunch
Refuse: 36 percent Skin

Papayas, raw
2 large (5-3/4" long x 3-1/4" dia) (760g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Dinner
Refuse: 33 percent Seeds and skin


If you want Pantry to sort in descending rather than ascending order,[7] use a capital letter to specify the name of the trait:

Example 2.28. Sorting in descending order

$ pantry --key Name \
--print name --print info --print blank \
diary 
Papayas, raw
2 large (5-3/4" long x 3-1/4" dia) (760g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Dinner
Refuse: 33 percent Seeds and skin

Bananas, raw
1 medium (7" to 7-7/8" long) (118g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Lunch
Refuse: 36 percent Skin

Apples, raw, with skin
3 large (3-1/4" dia) (669g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Breakfast
Refuse: 10 percent Core and stem


You can also specify more than one --key. Then Pantry will first sort foods using the first key, then by the second key, etc. For instance, here Pantry will sort foods first by their date traits. Foods with identical date traits will be sorted by name.

Example 2.29. Specifying more than one --key

$ pantry --search name \
"Snacks, popcorn, microwave, low fat" \
--change quantity 2 \
--change unit oz \
--change date 2008-06-20 \
--change meal Lunch \
--add diary master 
$ pantry --search name \
"Carbonated beverage, cola, contains caffeine" \
--change quantity 1 \
--change unit can \
--change date 2008-06-20 \
--change meal Lunch \
--add diary master 
$ pantry --key date --key name \
--print name --print info --print blank \
diary 
Apples, raw, with skin
3 large (3-1/4" dia) (669g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Breakfast
Refuse: 10 percent Core and stem

Bananas, raw
1 medium (7" to 7-7/8" long) (118g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Lunch
Refuse: 36 percent Skin

Papayas, raw
2 large (5-3/4" long x 3-1/4" dia) (760g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Dinner
Refuse: 33 percent Seeds and skin

Carbonated beverage, cola, contains caffeine
1 can 12 fl oz (368g)
Group: Beverages
Date: 2008-06-20
Meal: Lunch

Snacks, popcorn, microwave, low fat
2 oz (56.7g)
Group: Snacks
Date: 2008-06-20
Meal: Lunch


You might want to sort your foods in a particular order rather than alphabetical order. For instance, you might want to see foods sorted by meal. This would yield Breakfast, Dinner, Lunch if sorted alphabetically. To fix this, use the --list option. This allows you to list values for a particular trait. Foods will then be sorted in the order that you specified. (All foods having a trait whose value is not listed with the --list option will be sorted alphabetically, after foods whose trait values were specified with --list.)

Example 2.30. Using the --list option to sort foods

$ pantry --search date 2008-06-12 \
--list meal Breakfast \
--list meal Lunch \
--list meal Dinner \
--key meal \
--print name --print info \
--print blank diary  
Apples, raw, with skin
3 large (3-1/4" dia) (669g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Breakfast
Refuse: 10 percent Core and stem

Bananas, raw
1 medium (7" to 7-7/8" long) (118g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Lunch
Refuse: 36 percent Skin

Papayas, raw
2 large (5-3/4" long x 3-1/4" dia) (760g)
Group: Fruits and Fruit Juices
Date: 2008-06-12
Meal: Dinner
Refuse: 33 percent Seeds and skin


The --list option is always case sensitive; it is not affected by the --ignore-case option. The second argument to the --list option is just a plain string, not a regular expression pattern.

You may find that you want to add foods to a collection in a particular order and then see them reported in that order. Because Pantry stores foods in a manner that is for all practical purposes unordered, just adding foods to a collection in a particular order does not ensure they will be shown in that order in reports. Instead, that's what the --auto-order option is for. If you use it when adding a food to a collection, Pantry will automatically scan the collection for foods with identical date and meal traits. Pantry will then set the order trait of the food that is added to the collection so that the new food's order trait will come after all the other foods with identical date and meal traits. Then you can sort foods using the order trait to see them in the order in which you added them.

Phew! That's a long explanation. An example will help:

Example 2.31. Using the --auto-order option

$ pantry --search name "McDONALD'S, French Fries" \
--change quantity 1 \
--change unit large \
--change date 2008-06-21 \
--change meal Lunch \
--add diary --auto-order \
master 
$ pantry --search name "McDONALD'S, Double Cheeseburger" \
--change quantity 1 \
--change unit item \
--change date 2008-06-21 \
--change meal Lunch \
--add diary --auto-order \
master 
$ pantry --search date 2008-06-21 \
--search meal Lunch \
--key order \
--print name --print info --print blank \
diary 
McDONALD'S, French Fries
1 large serving (154g)
Group: Fast Foods
Date: 2008-06-21
Meal: Lunch
Order: 0010

McDONALD'S, Double Cheeseburger
1 item (173g)
Group: Fast Foods
Date: 2008-06-21
Meal: Lunch
Order: 0020


--auto-order does not require that you change either the date or meal traits of foods; it will work fine if those traits are left blank (all the foods in the starter_database file have blank date and meal traits.)

Approximations with the --refuse and --by-nut options

"There's good, and then there's good enough," I like to say. Pantry has two options that can help you when you are looking for approximations.

First the --refuse option. So far we have paid little attention to the refuse trait, which specifies the typical percentage of a food that is inedible. If you use this option, Pantry will reduce the quanitity of each food in the buffer by each food's percent-refuse trait. For example, apples range in size from tiny (about 6 oz, say) to enormous (over a pound!) If I am eating an apple, there are various ways I can use Pantry to find out the apple's nutrient content. First, I can look at it, guess its size, and then use the units report to find the appropriate available unit for Apples, raw, with skin. This requires that I make a good guess, but I am quite bad at guessing these things.

I could weigh the apple. The problem here is that the foods in the starter_database file have nutrient amounts for a given edible portion of food. These amounts don't include the core, stem, and seeds of the apple. So for the best accuracy I would have to cut up the apple and remove the core, stem, and seeds before weighing it.

Another alternative is the --refuse option. This way I can weigh the apple whole. Pantry will then deduct the appropriate amount from the quantity.

Example 2.32. Using the --refuse option

$ pantry --search name "Apples, raw, with skin" \
--refuse \
--change quantity 395 \
--change unit '^g$' \
--print name --print info master 
Apples, raw, with skin
355.500000000000000 g (355.5g)
Group: Fruits and Fruit Juices
Refuse: 10 percent Core and stem

Of course you can tack on options like --print goals and --goal in order to find more useful information about the apple.

There's no reason to use the --refuse option if you are using an available unit other than g, oz, or lb. In the starter_database file, all available units (other than g, oz, and lb) already represent the edible portion of a food. For instance, the large (3-1/4" dia) available unit for Apples, raw, with skin is 223g. This means that a typical large apple weighs 223 grams, without the core, stem and seeds. If you use --refuse here Pantry will think the food weighs too little. Thus using the --refuse option typically makes sense only if you stick foods on a scale. It is quite handy if, for example, you weigh a chicken drumstick before you eat it. Otherwise you'd have to weigh the drumstick, eat it, and then weigh the bone to figure out how much the meat weighed.

The other approximations tool is the --by-nut option. If you use it then Pantry will automatically adjust the quantity of a food so that a nutrient you specify will be of an amount that you specify.

For example, let's say I have just eaten half a cup of Haagen Dazs chocolate ice cream. I look on the container and find that I've just eaten 270 calories. But the starter_database file does not have Haagen Dazs. It does have Ice creams, chocolate, rich, but it doesn't have the same number of calories per gram. That bothers me because I want to know exactly how many calories I ate.[8] One way I could deal with this discrepancy would be to create a custom food for Haagen Dazs chocolate ice cream. We'll learn how to do that later. But for now I decide that Ice creams, chocolate, rich is good enough for my purposes. I figure I will just record that I ate 270 calories of Ice creams, chocolate, rich:

Example 2.33. Using the --by-nut option

$ pantry --search name \
"Ice creams, chocolate, rich" \
--by-nut Calories 270 \
--print name --print info \
--goal Calories 2800 \
--print goals \
--change date 2008-06-20 \
--add diary master 
Ice creams, chocolate, rich
105.882352941176478 g (105.882g)
Group: Sweets
Date: 2008-06-20
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                270    10    100   

As you can see Pantry adjusted the quantity of Ice creams, chocolate, rich so that it would be equal to 270 calories. --by-nut also lends itself to other uses, such as determining what quantity of a particular food will have a given amount of calories, fat, etc. so that you can meet whatever goals you have set for yourself.

The paste report

As you've been reading this chapter, one protest you might have is that a lot of Pantry commands require a lot of typing. I agree; the best solution, however, comes by using the features of your shell (such as functions, aliases, history, and variables) to help speed things up. We'll talk about those in the next chapter. Pantry does, however, have one innovation to help in a common situation. Often, you'll need to look through foods in the master collection in the starter_database file to find what you are looking for. Such a search involves two steps: first, you must find the right food; and second, often you must find the right available unit.

To merge these two steps into one, there is the paste report. It shows both the names of foods and their available units. The format of the report allows you to take the results and cut and paste them. Let's say for example I am looking for some sort of strawberry:

Example 2.34. The paste report

$ pantry --ignore-case \
--search name strawberries \
--search group fruit \
--print paste master | head 
pantry -xsn "Strawberries, frozen, unsweetened" -cu "berry" "master"
pantry -xsn "Strawberries, frozen, unsweetened" -cu "cup, thawed" "master"
pantry -xsn "Strawberries, frozen, unsweetened" -cu "cup, unthawed" "master"
pantry -xsn "Strawberries, frozen, unsweetened" -cu "g" "master"
pantry -xsn "Strawberries, frozen, unsweetened" -cu "lb" "master"
pantry -xsn "Strawberries, frozen, unsweetened" -cu "oz" "master"
pantry -xsn "Strawberries, frozen, unsweetened" -cu "package (20 oz)" "master"
pantry -xsn "Strawberries, frozen, sweetened, sliced" -cu "cup, thawed" "master"
pantry -xsn "Strawberries, frozen, sweetened, sliced" -cu "g" "master"
pantry -xsn "Strawberries, frozen, sweetened, sliced" -cu "lb" "master"

Then I can simply find the line with the right available unit and food name and paste that to my command line. I'll likely want to add additional options after I paste, such as --change quantity, --add, or --print. Unlike the units report, the paste report includes entries for the available units g, oz, and lb. Of course, to save space in the manual I stuck | head at the end; instead you'll likely want to send the output to your favorite pager, such as less.

In order to actually do the cutting and pasting, just use your favorite X terminal emulator, or the cutting and pasting features of GNU screen.

Saving and quitting

When you make changes to a database using the add option, those changes are made to the database that is currently in memory. Pantry does not write those changes to disk unless you tell it to. You can see whether you have unsaved changes to the currently open database by using the --status option:

Example 2.35. Seeing if there are unsaved changes

$ pantry --status 
Current filename: /home/massysett/pantry-git/data/starter_database
Collections: 
     8 diary (changed)
  7413 master 

Two options, --save and --save-as, will save your Pantry database to a file.[9] --save will save the database to the filename shown in the Current filename: part of the status report; if there is no current filename, Pantry will complain with an error message. --save-as takes a single argument, which is the name of the file you wish to use. --save-as will save your database to that file, and it will also change the current filename so that the database will be saved to that same file if you later use the --save option.

Here, the current filename is /usr/local/share/pantry/data/starter_database. That's a location that is only writeable by the root user, so if I use the --save option, Pantry will give me an error and quit. So instead I need to use --save-as to save the database to a file in my home directory:

Example 2.36. Using the --save-as option

$ pantry --save-as ~/my_pantry_file 

Finally you may want to shut down the server if you are done with Pantry. You do this with the --quit option: just run pantry --quit.

Additional commands to work with files

You've already learned all the options you'll typically need to work with Pantry files: --open, --save, and --save-as. I'll briefly mention a couple of others. First, one of Pantry's limitations is that it can work with only one database at a time, and one disk file holds one database. So there's no apparent way to take the contents of one database and merge it with another. Here's where the --read option comes in. The --open option reads the contents of a disk file into memory, clobbering whatever database was already in memory.[10] In contrast, the --read option takes the contents of a disk file and adds those contents to whatever is in memory. Using this you can, for example, merge the contents of two files.

The second option I'll mention here is simple: --close simply wipes the current database from memory, leaving you with a blank slate.

Oops! When things go wrong

Pantry takes a lot of command-line options, and sometimes you will get them wrong. Sometimes I get them wrong, and I wrote this thing. Sometimes you will also try to do something that Pantry does not allow. Examples include using a bad pattern for a regular expression (such as ab(c, which has an unmatched parenthesis) or giving a bad value for a numeric trait (such as attempting to change the quantity trait to a1). File operations have rich potential for errors--you might try to open a nonexistent file, open a file that is not a Pantry file, or save to a place where you don't have write permission.

Whenever Pantry can't do something for whatever reason, it will give you an error message and the client will quit with a non-zero exit status.[11] The server will keep running; it's only the client that will quit. Therefore you can easily try again.

If any error occurs, no changes will have been made to the database that is in memory or to any disk file.[12] That is, the --add, --edit, and --delete options will have had no effect. If an --open, --save, --save-as, or --read option fails for any reason, then the database that is in memory will remain unchanged.

The server should never quit unexpectedly. If it does, it is probably a bug; please report it to .



[3] As we will discuss later, to terminate the server, run pantry --quit.

[4] When I say non-option arguments, it's to distinguish these arguments from the arguments with leading single or double dashes.

[5] Pantry uses the regular expression routines that come with the standard UNIX C library. Pantry uses "extended" regular expressions; typically they are similar to what your egrep command uses. These regular expressions are less versatile than those Perl uses, but they are usually good enough and they are available on any Unix system.

[6] I do this with some frequency, so to make it a little easier to type I have alias -g G='\^g\$' in a file that defines Pantry shell functions, parameters, and aliases for me. This will only work in zsh.

[7] Pantry sorts in what has sometimes been called ASCIIbetical order. Pantry knows nothing about multibyte characters. See Appendix A, Pantry limitations.

[8] Actually Ice creams, chocolate, rich comes really close to Haagen Dazs, but since I'm so anal (wouldn't I have to be, to write a program like Pantry?) I want to be more exact.

[9] The database is written in plain ASCII text, but it's nothing you will want to edit directly.

[10] --open does not warn you before it clobbers what's in memory, even when the contents of the database in memory have not been saved. It assumes you know what you're doing.

[11] Currently the client will always exit with 1 if there was an error--any error. Maybe in future versions the exit code will change depending on the nature of the error.

[12] This is a dramatic improvement from earlier versions of Pantry, which had a variety of behaviors when errors happened.

Chapter 3. Pantry usage tips

There are a number of ways that you can make your use of Pantry more efficient, as this chapter will show you.

Use your shell

Pantry was designed to be used in concert with a good Unix shell. There are lots of good shells to pick from. GNU's Bourne Again Shell (bash) is the most common shell on Linux and it's probably the shell you are using if you do not know what shell you are using. bash is quite serviceable and powerful.

I'd like to recommend two alternatives to bash. zsh is an excellent shell for command-line junkies, and it is very well documented. zsh is available under a free software license, every major Linux distribution makes it available in its package repositories, and it is also available in Mac OS X. Another alternative is fish, the Friendly Interactive Shell. fish benefits from a sharp focus on usability. By breaking with compatibility with other Unix shells, fish is clear of clutter and predictable to use. fish is also free software. It's not as widely distributed as zsh, so you might have to compile it yourself.

If you are going to stick with bash or zsh, I highly recommend you read From Bash to Z Shell: Conquering the Command Line, by Kiddle, Peck and Stephenson. The authors are quite knowledgeable about Unix shells (Stephenson currently maintains zsh) and this book will teach you many useful tricks. It is well worth the price.

If you are a zsh user you're probably familiar with its powerful completion capabilities. You'll find a set of completions for pantry and pantryd at $PREFIX/share/pantry/scripts/_pantry.

History features

It will be particularly useful to you if you learn your shell's features for manipulating your command history. Often with Pantry I find myself re-running previous commands, with a minor tweak here and there. History features make this easy.

Aliases and functions

Another key shell feature is the ability to define aliases (which perform simple text substitution) and functions (which are programs in their own right.) I find both to be invaluable while using Pantry. I use functions to define my own custom commands to quickly add foods to a day's diary, something which I found to be nearly impossible with any other nutrient analysis software available. After using Pantry for a little while, you'll form your own ideas of what sort of functions will help you. For inspiration, you can take a look at the $PREFIX/share/pantry/scripts/zsh_functions file which is included in the Pantry distribution, where $PREFIX is the prefix you used when you ran the configure script. (By default it is /usr/local.) These are the functions I use. You might find them useful as-is, but I encourage you to modify them to fit your needs.

Variables and arrays

A final key shell feature is shell variables[13] and, in particular, arrays. The --list and --goal options are much more usable if you take advantage of arrays. For example, you might want to display several nutrients every time you print a goals report. As we saw in the last chapter, typing all these nutrients gets tiresome very quickly. The solution is to put the nutrients you want into an array.[14] Then, instead of typing all of them at the command line, you simply type the name of your array instead.

For reasons related to word splitting, I recommend you use zsh or fish if you're going to become an array user, as their syntax is a bit friendlier than that of bash and ksh.

Short options and abbreviations

For instructional purposes, all the examples in this manual use double-dashed long options. However, Pantry has single-dashed short options for all options you'll commonly use. To see what these are, refer to the Pantry man page or to pantry --help.

In many places, Pantry will accept abbreviations instead of full words. For example, for long options, you may type just enough to make yourself unambiguous. This means you can type pantry --q instead of pantry --quit. (pantry --qu or pantry --qui will work too.) You can also do this when you must specify a trait name. Because the first letter of each trait is unique, you can specify just a single letter. Thus, you can type pantry --search n bananas master instead of pantry --search name bananas master. Furthermore, you can abbreviate the names of reports for the --print option, and you can abbreviate collection names if you are specifying which collections to search (you can't abbreviate the argument to the --add option.)

That gives you lots of abbreviating options. For instance, instead of typing pantry --ignore-case --search name bananas --search group fruits --key name --print name master, you can instead run pantry -isn bananas -sg fruits -kn -pna m.[15]

Files and collections

Pantry is easiest to work with if you keep all your data in a single Pantry file. That's because Pantry does not make it very easy for you to move data from one file to another. Pantry has collections so that you can sort foods within a file in a way that you see fit. I find it easiest to keep three collections in my Pantry file. In two of these collections, master and quick, every food has a unique name trait. That makes it easy for me to find foods using simply their name trait. There are over 7000 foods in my master collection; it has every food that's in the starter_database file as well as other foods that I created on my own (we'll talk later about how you can create foods and recipes.) A second collection in my file, quick, holds only foods that I use frequently. There are about fifty foods in here currently. As with the master collection, every food in my quick collection has a unique name trait. Many of the foods in my quick collection already have their quantity and unit traits set to those that I commonly eat. Finally, I have a diary collection. When I add foods to my diary collection I set the date and meal traits to appropriate values.

This is just the way I do things; you might find a better way. For instance, maybe you will start a different collection for every day, or for every week. You might not find it necessary to keep a separate quick collection. You might keep a diary in the same collection as you keep all your other foods. It's up to you.

Using traits

For most traits, Pantry places no constraints on what values you can use. This gives you a great deal of latitude. For example, if you have several foods you eat together, one way to easily account for them in a diary is if you create a recipe, which we will talk about later. Another way is to simply change the group traits of these foods so they are unique and identical. For example, I often eat a particular cereal with a particular milk, so in my quick collection I have changed the group traits of these foods to Cereal and milk.

You can use whatever values you want for the date trait, but you will find that it is easiest to sort dates if you use a YYYY-MM-DD format.



[13] Or, what some shell documentation will call parameters.

[14] Under certain circumstances you can do this using regular, "scalar" variables rather than arrays, but you'll be making life hard on yourself.

[15] Pantry is liberal about whether spaces or equal signs must separate option arguments from the option itself; for instance, you can type either -pname, -p name, --print name, or --print=name.

Chapter 4. Creating new foods, and changing the nutrients and available units of existing foods

So far we've only dealt with foods that already exist in the starter_database file, which comes from data derived from the USDA National Nutrient Database for Standard Reference. We've copied these foods from one collection to another, often changing their traits along the way. But we haven't changed the nutrient content of these foods.

But what if you want to track information about a food that is not already in the USDA database? You might find there is already a food in the database that is close enough for your purposes. However, with Pantry you can easily create your own foods with their own nutrient data. Such foods are indistinguishable from those in the starter_database file--except for the fact that you created them yourself. In this chapter you'll learn how to create foods of your own.

You'll want to create a food if you already have nutrition information for what you are creating--from a label, say, or from a website. If you are combining multiple ingredients, you'll want to use a recipe instead, which we will discuss in the next chapter.

Create the food and its traits

You'll create foods with Pantry the same way you do anything else with Pantry: from the command line.[16] In this chapter we'll enter nutrition information for Heritage Flakes. There is something close in the starter_database file--Cereals ready-to-eat, wheat and malt barley flakes--but Heritage Flakes is a little higher in some nutrients, such as protein, and has twice as much fiber. You can get the nutrition information here.

To create a new food, use the --create option. This will give you a buffer with a single, blank food. Then you can use the --change option to change the traits to something appropriate, and the --add option to add the food to a collection. You can use the --print option to print the buffer, as usual. That gives us:

Example 4.1. Creating a new food

$ pantry --create \
--change name "Heritage Flakes" \
--change quantity 30 \
--change unit '^g$' \
--print name --print info \
--add master 
Heritage Flakes
30 g (30g)

We changed the quantity to 30 grams because that is the quantity that the food label is based upon.[17] It's essential that the quantity and units be correct when you add nutrient information.

Add available units

Next you can add available units to your food, if you wish. Pantry will automatically supply your food with the available units g, oz, and lb, so there is no need to add those. From the label we see that 3/4 of a cup of Heritage Flakes weighs 30 grams. This means a cup weighs 40 grams. Using this knowledge we can use the --change-avail-unit option. Its first argument is the name of an available unit that you wish to create or change, and its second argument is the weight of that available unit, in grams.

Example 4.2. Adding an available unit

$ pantry --exact-match \
--search name "Heritage Flakes" \
--change-avail-unit cup 40 \
--edit master 

Create nutrients

Next you can add nutrients. You can use whatever nutrient names you wish, but for consistency's sake you might wish to use names that are identical to those used in the starter_database file. (To get a list of all nutrient names used in the master collection of the starter_database file, you can run pantry --print Nuts master. That command might take several seconds to run, especially on a slow machine.)

On U.S. food labels, many nutrients are given as percentages. You might just enter these percentages if you wish. You can convert them to actual values using this chart. Right now we'll just skirt that issue by entering only macronutrients.[18] Be sure to use the --edit option so your changes are permanent.

Example 4.3. Adding nutrients

$ pantry --exact-match \
--search name "Heritage Flakes" \
--change-nut "Calories" 120 \
--change-nut "Total Fat, g" 1 \
--change-nut "Saturated Fat, g" 0 \
--change-nut "Trans Fat, g" 0 \
--change-nut "Cholesterol, mg" 0 \
--change-nut "Sodium, mg" 130 \
--change-nut "Total Carbohydrate, g" 24 \
--change-nut "Dietary Fiber, g" 6 \
--change-nut "Sugars, g" 4 \
--change-nut "Protein, g" 4 \
--edit master 

Check your work

That should do it. Let's make sure:

Example 4.4. Seeing the new food

$ pantry --exact-match \
--search name "Heritage Flakes" \
--print name --print info --print nuts \
master 
Heritage Flakes
30 g (30g)
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                120          100   
Cholesterol, mg                         0                  
Dietary Fiber, g                        6            100   
Protein, g                              4            100   
Saturated Fat, g                        0                  
Sodium, mg                              130          100   
Sugars, g                               4            100   
Total Carbohydrate, g                   24           100   
Total Fat, g                            1            100   
Trans Fat, g                            0                  

In this example, for instructional purposes we used more than one pantry command to add the traits, nutrients, and available units. You can do all this in one command, however. You can even add the food to collections and --print it, all in the same command.

The addFoods script

You might find it more convenient to enter the commands required into a simple shell script, since there are so many to type. Alternatively, you can use the addFoods script, which you will find in $PREFIX/share/pantry/scripts/addFoods, where $PREFIX is the prefix you used when you installed Pantry. (By default this is /usr/local.) This script takes the name of an input file, which is simply a number of zsh variables containing the data for the food. This script also automatically converts micronutrients, which are expressed on US food labels as percentages, to actual values. To get an idea how the script works, just take a look at the script itself. Alternatively, you will find a number of sample input files for this script in the $PREFIX/share/pantry/examples/foods directory. To get started you can just model your input after one of these files.

The addFoods script is written for zsh, so you'll have to install zsh in order to use it.

Commands to edit the nutrients and available units of foods

Pantry has a number of options to edit the nutrients and available units of existing foods. Changing nutrients and available units is similar to changing traits: Pantry makes the changes you wish, but only to foods that are in the buffer. To make your changes permanent, you need to use the --add or --edit option. We've already seen the --change-nut and --change-avail-unit options. These work not only for adding new nutrients or available units, but also for modifying existing ones. Remember that the first argument to --change-nut and --change-avail-unit is not a regular expression--it is the exact name of the nutrient you wish to add or change, and it is always case sensitive, even if you use the --ignore-case option.

If you wish to change the name of an existing nutrient, use --rename-nut. It takes two arguments. The first is a pattern for the nutrient name you wish to change. As with the --search option, this is a regular expression, unless you use the --exact-match option. --rename-nut also respects the --ignore-case option. The second argument is the new nutrient name.

Example 4.5. Using --rename-nut

$ pantry --search name "Heritage Flakes" \
--rename-nut "Total Carbohydrate, g" Carbs \
--print name --print info --print nuts \
master 
Heritage Flakes
30 g (30g)
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                120          100   
Carbs                                   24           100   
Cholesterol, mg                         0                  
Dietary Fiber, g                        6            100   
Protein, g                              4            100   
Saturated Fat, g                        0                  
Sodium, mg                              130          100   
Sugars, g                               4            100   
Total Fat, g                            1            100   
Trans Fat, g                            0                  

For each food in the buffer, the pattern given in the first argument to --rename-nut must match either no nutrients or one nutrient of each food. If the pattern matches no nutrients, Pantry will make no change to that food. If the pattern matches one nutrient, then Pantry will rename that nutrient. If the pattern matches more than one nutrient, Pantry will give you an error message and quit.

The --rename-avail-unit option renames available units (except for g, oz, and lb, which you cannot rename); otherwise, it is identical to the --rename-nut option. As with the --rename-nut option, the --rename-avail-unit pattern must match either zero or one available units for every food in the buffer (excluding g, oz, or lb); otherwise, Pantry will give you an error and quit.

Example 4.6. Using --rename-avail-unit

$ pantry --search name "Apples, raw, with skin" \
--rename-avail-unit large big \
--print name --print units master 
Apples, raw, with skin
   NLEA serving (242g)
   big (223g)
   cup slices (109g)
   cup, quartered or chopped (125g)
   extra small (2-1/2" dia) (101g)
   medium (3" dia) (182g)
   small (2-3/4" dia) (149g)

To delete nutrients, use --delete-nuts. This option takes one argument, a pattern for nutrients you wish to delete. This pattern is a regular expression, unless you use --exact-match, and it respects --ignore-case. It deletes every nutrient that matches the pattern, and it doesn't complain if no nutrients match the pattern:

Example 4.7. Using --delete-nuts

$ pantry --search name "Heritage Flakes" \
--delete-nuts Fat \
--print name --print nuts \
master 
Heritage Flakes
Nutrient name                           Amount %G    %T    
-----------------------------------------------------------
Calories                                120          100   
Cholesterol, mg                         0                  
Dietary Fiber, g                        6            100   
Protein, g                              4            100   
Sodium, mg                              130          100   
Sugars, g                               4            100   
Total Carbohydrate, g                   24           100   

The --delete-avail-units option deletes available units, other than g, oz, and lb. In all other respects it is identical to the --delete-nuts option:

Example 4.8. Using --delete-avail-units

$ pantry --search name "Apples, raw, with skin" \
--delete-avail-units large \
--print name --print units master 
Apples, raw, with skin
   NLEA serving (242g)
   cup slices (109g)
   cup, quartered or chopped (125g)
   extra small (2-1/2" dia) (101g)
   medium (3" dia) (182g)
   small (2-3/4" dia) (149g)



[16] This differs dramatically from older versions of Pantry, which used XML files for this purpose.

[17] You might wonder why we don't say that the quantity is 3/4 and the unit is cup. That's because later we'll discuss adding available units, which is what you'll have to do so that Pantry knows how much a cup of Heritage Flakes weighs.

[18] Pantry comes with a script that helps you enter new foods, and it converts these percentages to actual values. We'll talk about this script later.

Chapter 5. Creating recipes

Creating new foods works great if you already know the nutrient content of a food--if, for example, you can pull the information from a label. Recipes, on the other hand, are ideal if you are creating a food from other foods and you don't know the nutrient content of the final food.

In Pantry, recipes are mostly like other foods. They are different in that they have two additional traits: yield and instructions. yield indicates the total weight, in grams, of one batch of this recipe. This is quite handy because recipes often lose water as you cook them. Of course you can only know the exact yield after you have cooked a recipe and have weighed it. If you do not supply a yield trait for a recipe, Pantry will guess the yield by adding up the weight of all the recipe's ingredients. instructions is simply food preparation notes, or whatever you want.

Create the recipe and its traits

This step is similar to the first step of creating a food: you use the --create option, and then you set the traits as you wish.

Example 5.1. Creating a recipe

$ pantry --create --change name "Easy Corn Bread" \
--change group "Baked Products" \
--change quantity 50 \
--change unit '^g$' \
--change instructions 'Heat oven to 400
degrees F. Grease 8- or 9-inch pan. Combine
dry ingredients. Stir in milk, oil, and
egg, mixing just until dry ingredients are
moistened. Pour batter into prepared pan.
Bake 20 to 25 minutes or until light golden
brown and wooden pick inserted in center
comes out clean. Serve warm.' \
--add master 

Add ingredients

To add ingredients to a food, you use the --add-ingredients option, which takes a single argument, which is the name of the collection to add foods from.[19] Pantry adds all the foods from the collection as ingredients. Thus, the easiest way to create recipes is to add all the ingredients to a temporary collection--ingredients, perhaps--and then use that collection as an argument to --add-ingredients. You can just delete the collection with --delete when you are done.

Example 5.2. Adding ingredients to a single collection

$ pantry --exact-match \
--search name \
"Wheat flour, white, all-purpose, enriched, unbleached" \
--change quantity "1 1/4" --change unit cup \
--add ingredients master 
$ pantry --exact-match \
--search name \
"Cornmeal, whole-grain, yellow" \
--change quantity "3/4" --change unit cup \
--add ingredients master 
$ pantry --exact-match \
--search name \
"Sugars, granulated" \
--change quantity "1/4" --change unit cup \
--add ingredients master 
$ pantry --exact-match \
--search name \
"Leavening agents, baking powder, double-acting, straight phosphate" \
--change quantity "2" --change unit tsp \
--add ingredients master 
$ pantry --exact-match \
--search name \
"Salt, table" \
--change quantity "1/2" --change unit tsp \
--add ingredients master 
$ pantry --exact-match \
--search name \
"Milk, reduced fat, fluid, 2% milkfat, with added vitamin A" \
--change quantity 1 --change unit cup \
--add ingredients master 
$ pantry --exact-match \
--search name \
"Oil, corn and canola" \
--change quantity "1/4" --change unit cup \
--add ingredients master 
$ pantry --exact-match \
--search name \
"Egg, whole, raw, fresh" \
--change quantity 1 --change unit large \
--add ingredients master 

Okay, now we can add the ingredients to the food itself. After adding them to the food we have no use for the collection so we can just delete it.

Example 5.3. Add ingredients to the food

$ pantry --search name "Easy Corn Bread" \
--add-ingredients ingredients \
--edit master 
$ pantry --delete ingredients 

Add available units

You do this just as you would for a food. We won't add any available units here, but you will often find it is handy to add an available unit for serving. To do this you can simply divide a recipe's yield by the number of servings. In the next section you'll see how to find a food's estimated yield if you haven't weighed the yield yourself.

Seeing your new recipe

In order to see your new recipe, you use the recipe report. This report shows the yield trait, ingredients, and instructions trait for a recipe. Recipes and foods are fully interchangeable in Pantry--for instance, a recipe can be the ingredient for another recipe.

Example 5.4. The recipe report

$ pantry --search name "Easy Corn Bread" \
--print name --print info --print recipe \
master 
Easy Corn Bread
50 g (50g)
Group: Baked Products
Yield: 659.95g (estimated)
1 1/4 cup (156g, 5.51oz) Wheat flour, white, all-purpose, enriched, unbleached
3/4 cup (92g, 3.23oz) Cornmeal, whole-grain, yellow
1/4 cup (50g, 1.76oz) Sugars, granulated
2 tsp (9g, 0.32oz) Leavening agents, baking powder, double-acting, straight phosphate
1/2 tsp (3g, 0.11oz) Salt, table
1 cup (244g, 8.61oz) Milk, reduced fat, fluid, 2% milkfat, with added vitamin A
1/4 cup (56g, 1.98oz) Oil, corn and canola
1 large (50g, 1.76oz) Egg, whole, raw, fresh

Heat oven to 400
degrees F. Grease 8- or 9-inch pan. Combine
dry ingredients. Stir in milk, oil, and
egg, mixing just until dry ingredients are
moistened. Pour batter into prepared pan.
Bake 20 to 25 minutes or until light golden
brown and wooden pick inserted in center
comes out clean. Serve warm.

For ingredients, Pantry prints the quantity trait, the unit trait, and the name trait. Pantry will print the comment trait's value in parentheses, if the comment trait is set at all. Pantry prints ingredients by sorting their order traits in ascending order, even though Pantry does not show the order traits for the ingredients. So, if you want to ensure that your ingredients are shown in a certain order, set your order trait for each ingredient accordingly.

A recipe's nutrient makeup is determined by all its ingredients. The nutrient makeup is scaled depending upon the yield trait, which is why Pantry will be more accurate if you weigh the yield of a recipe and enter it in. If the yield trait of a recipe is not set (of if you explicitly set it to zero) then in the recipe report Pantry will show an estimate for the recipe's yield, as it has done here. Pantry gets this estimate by adding the weight of all of a recipe's ingredients. Typically this estimate will be high, as cooking typically causes some of the water in a recipe to evaporate.

The addRecipes script

Since you have to type so much in order to add a recipe, you might want to put the commands in a simple shell script. Also, just as there is an addFoods script, there is also an addRecipes script. The script allows you to define a few shell variables in a file, which you then feed to the script in order to create your recipe. You'll find it at $PREFIX/share/pantry/scripts/addRecipes, and there are sample input files at $PREFIX/share/pantry/examples/recipes, where $PREFIX is the prefix you used when you installed Pantry. (It defaults to /usr/local.)

Like the addFoods script, the addRecipes script is written for zsh.

If you use the addRecipes script, also take a look at the ingrlist script, which will help you as you look up ingredients to add to input files for addRecipes.

Editing recipes

Recipes and foods in Pantry are nearly fully interchangeable. You can edit the traits and available units for a recipe in the same way as you do for a food. Nutrients, however, are a bit different. In a regular food, you input all the nutrient data. For a recipe, the nutrient data is typically calcualted from the ingredients. You can use --change-nut on a recipe. This will create a nutrient that will override the automatically-calculated nutrient of the same name, if there is one. For recipes, --rename-nut only works for nutrients you have entered using --change-nut, and --delete-nuts only deletes nutrients that you have set using --change-nut or --rename-nut. If you delete a nutrient you have set using --change-nut or --rename-nut, Pantry will then revert to using the automatically-calculated nutrient, if there is one.



[19] You can abbreviate the argument to the shortest unambiguous name for the collection, just as you can abbreviate collections that are positional arguments to the pantry command.

Appendix A. Pantry limitations

Pantry isn't perfect. It has some limitations you might want to know about.

No multibyte or locale awareness

Pantry is horribly U.S. centric. It knows nothing about multibyte character encodings, such as UTF-8. Furthermore, it knows nothing about locales, so collation is performed in what has sometimes been called ASCIIbetical order.

Strictly speaking you could use any encoding with Pantry, as long as it is a single-byte one. For instance, Pantry would have no problem with characters from the ISO-8859-1 character set. However, I recommend you stick with US-ASCII, for two reasons. First, most Linux distributions these days use UTF-8 for their terminal encoding. If you use characters solely from the ASCII character set, then UTF-8 is identical to ASCII. However, if you use characters from ISO-8859-1, and your terminal is set to UTF-8, then you will really be using multibyte characters, which Pantry does not know how to handle. Second, even if you get your terminal set up correctly to use a non-ASCII single-byte encoding, your file may behave differently if you later use it on a different computer with a different terminal encoding. ASCII, on the other hand, is an encoding which will work nearly anywhere.

Converting Pantry to use multibyte encodings correctly would not be terribly difficult. Pantry could ensure that all input data is converted to UTF-8 for internal use, and then convert it to the proper encoding when sent to the user's terminal. Another issue would be regular expressions. I've never seen regular expression routines from a UNIX standard C library that claim to be multibyte aware, so they probably are not. A straightforward solution would be to use PCRE, which can handle UTF-8.

The reason I haven't made Pantry handle multibyte properly is because all the documentation is in English and the interface is in English. This is not likely to change soon, as Pantry has no community of users to translate it, and English is the only language I know. If you are fluent in written Enlish, then likely it is not much of a limitation to use only US-ASCII with Pantry. I could one day make Pantry multibyte aware, if it seemed someone cared about that and if I had lots of free time.

High RAM usage

Pantry can use lots of memory. Well, whether it is "lots" depends on what you think a lot is. When I open the starter_database file on my computer, Pantry consumes about 30 MB of memory. I don't think that is too bad, but then, my least capable computer has 512 MB of RAM, and typically I don't even use half of that.

Pantry consumes so much memory because it stores so much data. Most of the foods in the starter_database file have a few dozen nutrients; that's what consumes the vast majority of storage space. Therefore, if you want to keep all the foods in the starter_database file but you want to cut memory usage, the easiest way to do it is to delete nutrients you don't need, which of course is easy with the --delete-nuts option. The less data you store, the smaller Pantry's memory footprint will be.

A great deal of code in Pantry 26 was rewritten so that Pantry is more frugal with memory. Though the starter_database file currently consumes 30 MB of memory on my machine, with older versions of Pantry this was 55 MB. Pantry 26 is also a bit faster than older versions of Pantry, too.

Only one file at a time may be open

In Pantry each server can work only with one file at a time. This could possibly be changed, but right now I don't see how changing this would do anything other than make the user interface more complex.

Size of collections, number of collections, number of nutrients, etc.

There are limitations to how many foods you can have in a collection, how many collections you may have in a single database, etc. These limitations will vary depending upon the nature of your standard C++ library. On my machine, for example, I can have (in theory) about 4 billion collections. Each collection can have a much lower number foods: only about 1 billion. For all practical purposes you'd run out of memory before you hit these limitations.

Numbers are approximations

Gasp! This is a nutrition analysis software package, and the numbers are approximations?! Yes. Internally Pantry uses floating point numbers. Such numbers are, by their very nature, approximate. We're talking typical approximations on the order of, for example, fractions of a calorie--not tens of calories or even a single calorie.

Though Pantry could be made more precise, this would come at the expense of more memory usage and more code. Furthermore, the only result would be precise calculations of nutrition data--data which is, by its very nature, also approximate. So at this point I'm inclined to say that Pantry's approximations are "good enough."

Appendix B. How the USDA National Nutrient Database for Standard Reference became the starter_database file

If you are curious about how the data from USDA's National Nutrient Database is translated into a form Pantry can understand, and whether any data was lost along the way, you've come to the right place.

USDA releases its database in the form of about a dozen plain text files, which you can download from the USDA website. If the data in Pantry looks familiar, it's because this USDA data forms the basis for pretty much any food database you will find in the US, either on the Web or on your desktop, in free software and in proprietary products.

I have written a zsh script to convert the USDA database into a series of over 7,000 Pantry commands--one command for each food in the database. You can find the script at $PREFIX/share/pantry/scripts/convert_sr.zsh.[20] This script renames some nutrients from names like Fatty acids, total trans to Trans Fat. It also discards some of the gram weights (or, in Pantry lingo, available units) from the WEIGHT.txt file. For example, the WEIGHT.txt file contains weights such as lb which Pantry provides automatically. Also, it provides some weights where the quantity is more than one--it might have a weight for, say, 2 slices of pizza rather than for 1 slice of pizza. I thought hard about what to do with data like this before finally deciding to just discard it. The only accurate way to keep this data would be to manually go through it and edit the descriptions accordingly.

The script spits the Pantry commands to standard output, which I then save to a file and use to create the starter_database file. You can even do it yourself. You might do this if, for instance, USDA has released a new database and you don't want to wait for me to get around to releasing a new version of Pantry. Beware, though: the convert_sr.zsh file works fine with SR20 and SR21 (USDA calls the database simply "SR"), but future SR releases might change their format and break the script. I doubt this would happen, but it's possible. Also, an earlier release of SR20 had small irregularities in the data that completely broke this script, but a subsequent release of SR20 fixed this problem.

If you want to see a list of all the nutrients in the starter_database file, open it and run pantry -p Nuts master. It will be obvious how these nutrients match up with those in SR, even though I changed the names a bit. This command may take a few seconds to run, especially on slow machines.



[20] This is a huge change from earlier versions of Pantry, which included Python code to import the USDA database. I've found these sorts of tasks to be easiest with zsh, though ksh would work fine too. Maybe Perl would work well, but I've never had any desire to learn Perl. C++ would be very nasty for a task such as this.

Appendix C. Reference pages

Table of Contents

pantry — nutrient tracking and analysis
pantryd — nutrient tracking and analysis server

This appendix contains reference pages for the commands that Pantry uses. They are identical to the man pages; indeed, the man pages and this document are generated from the same source.

Name

pantry — nutrient tracking and analysis

Synopsis

pantry [options...] [collection...]

Description

pantry copies foods from collections into a buffer. All foods are copied, unless one or more --search options are specified, in which case only foods that match the patterns of every --search option are copied. pantry then changes every food in the buffer using any --change options specified as well as any options for changing nutrients, available units, and ingredients.

If --edit or --delete is specified, pantry deletes the unchanged foods from the corresponding original collections. If --edit is specified, pantry adds changed foods to corresponding original collections.

If --print REPORT is specified, buffer is printed using REPORT Buffer is unsorted unless one or more --key TRAIT is specified. Sorting may be affected by one or more --list options.

If --add COLLECTION is specified, each food in the buffer is added to COLLECTION.

pantry communicates with a pantryd server, see pantryd(1).

Options

TRAIT is any one of:

  • name

  • group

  • quantity

  • unit

  • date

  • meal

  • comment

  • order

  • refuse

  • percent-refuse

  • yield

  • instructions

TRAIT names may be abbreviated.

PATTERN is an extended regular expression, unless --ignore-case is on.

Most options other than file and server control options may appear on the command line more than once; the effect of multiple options is cumulative.

File and server control

--open filename

Close currently open database and open filename

--read filename

Append contents of filename to currently open database

--close

Close currently open database

--save

Save currently open database

--save-as filename

Save currently open database under a different filename

--quit

Shut down server

--status

Display server status and database information: names of collections in database and the number of foods in each collection, and what filename will be used if --save option is used

Food selection

--search TRAIT PATTERN , -s TRAIT PATTERN

Include in buffer only foods whose TRAIT matches PATTERN.

Changing food traits

--change TRAIT string , -c TRAIT string

Change TRAIT string. If TRAIT is unit, string is a pattern that must match exactly one of the food's available units. If TRAIT is quantity or unit, string must be convertible to a non-negative number. If TRAIT is percent-refuse, string must be convertible to a number between 0 and 100, inclusive.

--refuse , -r

Reduce food quantity by percent refuse.

Changing nutrients, available units, and ingredients

--change-nut string number

Change nutrient whose name is string to number.

--rename-nut pattern string

Rename nutrient whose name matches pattern to string.

--delete-nuts PATTERN

Delete all nutrients matching PATTERN.

--change-avail-unit string number

Change available unit whose name is string to number.

--rename-avail-unit pattern string

Rename available unit whose name matches pattern to string.

--delete-avail-units PATTERN

Delete all available units matching PATTERN.

--add-ingredients COLLECTION

Add ingredients from COLLECTION.

--delete-ingredients PATTERN

Delete ingredients whose name trait matches PATTERN.

Search and edit options

--ignore-case , -i

All patterns are case insensitive.

--exact-match , -x

All patterns must exactly match their subjects (turns off regular expressions).

--edit

Edit foods in place

--delete

Delete matching foods

--create

Create a new food from scratch. When this option is used, Pantry does not copy foods from any collections specified on the command line, and the --edit and --delete options are ignored.

--limit number

Limit number of foods in buffer to number

Reporting

--print report , -p report

Print report (see "Reports" section below)

--key TRAIT , -k TRAIT

Use TRAIT as a sorting key. If the first letter of TRAIT is lowercase, sort in ascending order; if the first letter of TRAIT is uppercase, sort in descending order.

--goal nutrient-name amount , -g nutrient-name amount

Add a nutrient intake goal for use by the nutrient-related reports, where nutrient-name is the nutrient for which you wish to add a goal, and amount is a string, convertible to a non-negative number, that is the amount of the goal.

--list TRAIT string , -l TRAIT string

Add string to the list of strings that will be used when TRAIT is used as a sorting key. When TRAIT is equal to one of these values, it will be sorted in the order specified.

Adding results to collections

--add COLLECTION , -a COLLECTION

Add buffer to COLLECTION.

--auto-order , -o

When adding each food to collections specified with --add, pantry will search the collection for other foods with identical date and meal traits. The result will be sorted in ascending order by the order trait. If the highest food's order trait matches the regular expression ^[0-9]4$, then pantry will take the highest food's order trait, remove any leading zeroes, remove the last digit, and increment the result by one. The result is multiplied by ten, and then is left-padded with zeroes so that it is four characters long. pantry will then change the order trait of the food to the result before adding it to the collection.

If there are no foods with identical date and meal traits, then pantry will set the food's order trait to 0010.

Meta

--help , -h

Display brief help.

--version , -v

Display Pantry version.

--copyright

Display copyright information.

Reports

Two types of reports are available. Food reports are printed once per food in the buffer. Summary reports are printed once for the entire buffer. To print more than one report, use multiple --print options. Report names may be abbreviated with an unambiguous specification of the first letters of the report. The following reports are available:

Food reports

name

Food names

info

All traits other than the name, yield, and instructions.

recipe

yield and instructions traits, and the recipe's ingredients. Ingredients are sorted according to their order traits.

units

Available units. g, oz, and lb are not printed as these are available for every food.

paste

Each food name, printed with one available unit per line; quoted so that output may be easily pasted into subsequent pantry commands.

blank

A blank line

nuts

All of a food's nutrients

goals

Nutrients for which there is a goal specified with --goal

Summary reports

groups

Number of foods in each food group, as specified by each food's group trait

Nuts

Sum of all nutrients in the buffer

Goals

Sum of all nutrients in the buffer for which there is a --goal

Environment variables

PANTRY_SOCKET

If this environment variable is specified, pantry will use the path contained therein as the filename of the socket where it will attempt to connect to the pantryd server. PANTRY_SOCKET should contain the entire path (beginning with / ) and filename, not just the directory for the socket. The server must have already been started with an identical value in its PANTRY_SOCKET environment variable.

If this environment variable is not specified, pantry will attempt to connect to a server at the socket named $HOME/.pantrySocket.

Bugs

Please help find them. Report bugs to .

Pantry has known limitations; see the Pantry User Guide for details.


Name

pantryd — nutrient tracking and analysis server

Synopsis

pantryd [options...]

Description

pantryd is the server with which pantry communicates. pantryd must be running in order for any pantry commands to work.

To start a server, simply execute pantryd. This will start a new server in the background, returning you to your command prompt. This server will keep running even if you logout of the shell from which you started the server. To kill the server, run pantry --quit.

Options

--foreground , -f

Run server in the foreground (useful for debugging)

--help , -h

Show brief help and exit

Environment variables

PANTRY_SOCKET

If this environment variable is specified, pantryd will use the path contained therein as the filename of the socket where it will listen for connections. PANTRY_SOCKET should contain the entire path (beginning with / ) and filename, not just the directory for the socket. To communicate with the server, you'll need to make sure that subsequent invocations of pantry also have their PANTRY_SOCKET environment variable set to an identical value.

If this environment variable is not specified, pantryd will listen for connections on a socket named $HOME/.pantrySocket.

Bugs

Report any bugs to .