DEV Community

Miguel Mota
Miguel Mota

Posted on

How Unix programmers at restaurants search menus for their favorite plate

A Unix programmer heads over to the local diner to get something to eat for lunch. He, or Bob as he prefers, knows better than to manually scan the entire menu with his eyeballs because it's inefficient. Bob knows that there's a better way to automate the process in searching for what he wants to eat.

Last time he was here he had a pretty good pasta-and-shrimp plate for under 10 bucks.

Bob wonder's if this same dish is still available. He pops open his laptop running Linux and scrapes the restaurant website menu table into a plain text file.

menu.txt

the menu

steak burrito $11.95
pasta and shrimp $9.75
caesar salad $6.50

Now that Bob has the menu, he does a grep search for the pasta-and-shrimp plate:

$ cat menu.txt | grep shrimp

pasta and shrimp $9.75

So far so good. He filters for the price column by using awk and the NF variable (which is the number of columns fields available) in order to get the last column containing the prices:

$ cat menu.txt | grep shrimp | awk '{print $NF}'

$9.75

The starvation is kicking in and he's typing furiously by now. Bob proceeds with sed to turn the dollar amount into an integer by replacing everything except for what's inbetween the dollar symbol and decimal period. He'll use a capturing group and replace the contents with the first capture group \1:

$ cat menu.txt | grep shrimp | awk '{print $NF}' | sed -E 's/\$([0-9]+)\..*/\1/g'

9

Finally, using the handy test command and the less-than flag -lt, Bob can check whether the price is less than 10 with the help of xargs to pipe the value as the first argument to test:

$ cat menu.txt | grep shrimp | awk '{print $NF}' | sed -E 's/\$([0-9]+)\..*/\1/g' | xargs -I {} test {} -lt 10 

But wait there's no output! Actually, test returns an exit status code of 0 if the condition passes or 1 if no match.

Bob simply echo's Available if the previous command was successful by using &&, otherwise he'll echo :( by using the double pipe || if it was not successful:

$ cat menu.txt | grep shrimp | awk '{print $NF}' | sed -E 's/\$([0-9]+)\..*/\1/g' | xargs -I {} test {} -lt 10 && echo 'Available!' || echo ':('

Available!

Voila! there it is, the desired pasta-and-shrimp plate is still the under ten bucks. Bob is happy and proceeds to order his favorite dish.

(hope you liked this intro post to unix pipes and bash commands!)

Latest comments (33)

Collapse
 
lcfd profile image
Luca Fedrizzi

Awesome!

Collapse
 
gmanon profile image
GManon

Hilarious!

Collapse
 
jeffprestes profile image
Jeff Prestes

hahaha, it's amazing! Congratulations.

Collapse
 
rdcloud85 profile image
Rick Cloud

Or, he could merely 'read' visually the menu??? Didn't realize this was a lesson in Unix coding until the end... :-) Laugh at me...

Collapse
 
pawail profile image
Pawail A. Qaisar

Why.

Collapse
 
catchenal profile image
Cat Chenal • Edited

Given this menu:

ps1$cat menu.txt

the menu

steak burrito $11.95
pasta and shrimp $9.75
caesar salad $6.50
shrimp salad $9.99
alfredo shrimp $10

My Nix programmer does this:

awk -F$ '/shrimp/{if ($NF < 10){ print $1}}' menu.txt

pasta and shrimp
shrimp salad

awk rules!

Collapse
 
labibllaca profile image
labibllaca

if you are looking for meals under 10 bucks, as shown in ($NF < 10), why isn't caesar salad($6.50) in the output ?

Collapse
 
tameware profile image
tameware

It took me a while to realize that the price is truncated to an integer only because 'test' can't handle decimals. That might deserve a mention.

Collapse
 
sh0kry profile image
Mohamed Shoukry

Bob should've rounded up. He probably ran off when he remembered he didn't factor taxes in!
Oh & btw, he should've done a case insensitive grep grep -i shrimp menu.txt. Although if he's using awk anyway, then he might have included that there too and avoid all those unnecessary pipes! awk '$0~/shrimp/{print $NF}

Collapse
 
ppetermann profile image
ppetermann

In a lot of countries the tax is part of the price

Collapse
 
slamotte profile image
Steve Lamotte

I don't like how there's no code for how to scrape the website into menu. txt. Incomplete solution! ;-)

Collapse
 
moopet profile image
Ben Sinclair

| rev | cut -d\ -f1 | rev

troll face

Collapse
 
agusnavce profile image
Agustin Navcevich

This is why two unix programmers will never eat together, because they will start to discuss which is the best way to order the shrimps

Collapse
 
hoffmann profile image
Peter Hoffmann

Why are you guys alwas using awk for field separation? There ist cut -d" " -f3 that is nice as well

Collapse
 
peterbertok profile image
Peter Bertok • Edited

The equivalent is much more readable with PowerShell:

$shrimp = Get-Content menu.txt | Select-String 'shrimp'
$price = $shrimp | ForEach-Object { $cols = $_ -split ' '; $cols[-1] }
$under10 = [decimal]$price.Substring(1) -lt 10
if ( $under10 ) { 'Available!' } else { ':(' }

Of course, you can use aliases to make this a bit "shorter", but then we're back in the world of Unix, where precious bytes have to be saved to achieve acceptable performance on 300 baud Teletype terminals:

$p = gc menu.txt | sls 'shrimp' | % { $c = $_ -split ' '; $c[-1] }
if ([decimal]$p.Substring(1) -lt 10) {'Available!'} else {':('}

Collapse
 
swarupkm profile image
Swarup Kumar Mahapatra

This article is awesome. It really shows all the possibilities in Linux. I am quite surprised by the comments here where people are trying to correct you. Anyways, good job

Collapse
 
chbarts profile image
Chris Barts

Some comments may only be visible to logged-in visitors. Sign in to view all comments.