Bash: Handling Command Not Found
After a recent O/S version upgrade (to openSUSE 11.2) I noticed that bash started being a bit more intelligent when I did something stupid: it started giving me a useful error message when I typed the name of a command that wasn't in my PATH but that was in an "sbin" directory. My reaction at the time was "huh, that's nice", but today I decided I needed a bit more information.
As an example of this behavior, if I type ifconfig while not logged in as root I get the get the following:
$ ifconfig
Absolute path to 'ifconfig' is '/sbin/ifconfig', so running it may require superuser privileges (eg. root).
Which is certainly more useful than a "command not found" message.
Turns out that this capability is a standard feature of bash. From bash's man page:
... A full search of the directories in PATH is performed only if the command is not found in the hash table. If the search is unsuccessful, the shell searches for a defined shell function named command_not_found_handle. If that function exists, it is invoked with the original command and the original command's arguments as its arguments, and the function's exit status becomes the exit status of the shell. If that function is not defined, the shell prints an error message and returns an exit status of 127.
I'm not sure if that's a new feature of bash or if it's just something that's recently implemented in openSUSE.
A quick grep in /etc discovered where it was happening. The function itself is in /etc/bash_command_not_found and that function gets included (if it exists) in your bash session via /etc/bash.bashrc.
The function itself is not that complex but there are a couple of useful tidbits that I wanted to point out as a sidebar. The following code determines if the invoking shell was executed from Midnight Commander or is taking input from a pipe:
# do not run when inside Midnight Commander or within a Pipe
if test -n "$MC_SID" -o ! -t 1 ; then
echo $"$1: command not found"
return 127
fi
And the following determines if the invoking shell is a sub-shell:
# do not run when within a subshell
read pid cmd state ppid pgrp session tty_nr tpgid rest < /proc/self/stat
if test $$ -eq $tpgid ; then
echo "$1: command not found"
return 127
fi
End of sidebar.
At the end of the function there's some code that uses /usr/bin/command-not-found (a python script) to lookup commands in installable packages (via zypper), but you need to set an environment variable (COMMAND_NOT_FOUND_AUTO) to activate it, and of course you need to have python installed. To test this try the following:
$ export COMMAND_NOT_FOUND_AUTO=1
$ pascal
pascal: command not found
$ gcj
The program 'gcj' can be found in the following package:
* gcc-java [ path: /usr/bin/gcj, repository: zypp (repo-oss) ]
Try installing with:
sudo zypper install gcc-java
Since this command-not-found functionality is handled by a bash function, you can of course replace the system installed function (if one exists on your system) with one of your own design. All you need is to include it in your .bashrc script. The entire version of openSUSE's script follows:
command_not_found_handle() {
export TEXTDOMAIN=command-not-found
local cmd state rest
local -i pid ppid pgrp session tty_nr tpgid
# do not run when inside Midnight Commander or within a Pipe
if test -n "$MC_SID" -o ! -t 1 ; then
echo $"$1: command not found"
return 127
fi
# do not run when within a subshell
read pid cmd state ppid pgrp session tty_nr tpgid rest < /proc/self/stat
if test $$ -eq $tpgid ; then
echo "$1: command not found"
return 127
fi
# test for /usr/sbin and /sbin
if test -x "/usr/sbin/$1" -o -x "/sbin/$1" ; then
if test -x "/usr/sbin/$1" ; then prefix='/usr' ; else prefix='' ; fi
echo $"Absolute path to '$1' is '$prefix/sbin/$1', so running it may require superuser privileges (eg. root)."
return 127
fi
if test -n "$COMMAND_NOT_FOUND_AUTO" ; then
# call command-not-found directly
test -x /usr/bin/python && test -x /usr/bin/command-not-found && /usr/bin/python /usr/bin/command-not-found "$1" zypp
else
# print only info about command-not-found
echo -e $"If '$1' is not a typo you can use command-not-found to lookup the package that contains it, like this:\n cnf $1"
fi
return 127
}
Mitch Frazier is an Associate Editor for Linux Journal.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- RSS Feeds
- New Products
- Using Salt Stack and Vagrant for Drupal Development
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- Validate an E-Mail Address with PHP, the Right Way
- Readers' Choice Awards
- New Products
- This is the easiest tutorial
27 min 32 sec ago - Ahh, the Koolaid.
6 hours 6 min ago - git-annex assistant
12 hours 5 min ago - direct cable connection
12 hours 28 min ago - Agreed on AirDroid. With my
12 hours 38 min ago - I just learned this
12 hours 42 min ago - enterprise
13 hours 12 min ago - not living upto the mobile revolution
16 hours 4 min ago - Deceptive Advertising and
16 hours 39 min ago - Let\'s declare that you have
16 hours 40 min ago
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.



Comments
command_not_found_handle used for oo-style
Try the oobash! It is an oo-style string library for bash 4. It has support for german umlauts. It is written in bash. Many functions are available: -base64Decode, -base64Encode, -capitalize, -center, -charAt, -concat, -contains, -count, -endsWith, -equals, -equalsIgnoreCase, -reverse, -hashCode, -indexOf, -isAlnum, -isAlpha, -isAscii, -isDigit, -isEmpty, -isHexDigit, -isLowerCase, -isSpace, -isPrintable, -isUpperCase, -isVisible, -lastIndexOf, -length, -matches, -replaceAll, -replaceFirst, -startsWith, -substring, -swapCase, -toLowerCase, -toString, -toUpperCase, -trim, and -zfill.
Look at the contains example
###############################
First call the constructor:
[Desktop]$ String a testXccc
Now use object.method:
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false
http://sourceforge.net/projects/oobash/
The command-not-found handler
The command-not-found handler originated from Ubuntu, I think, and was accepted into bash somewhere in v3+, but didn't pass the arguments to the function until bash v4.
Well known feature of packagekit copied from debian
http://blogs.gnome.org/hughsie/2008/12/05/command-not-found/
Why no gravatar support for comments? I don't want a login account. It's another password I have better things to do than remember.
Don't have to remember...
...just get a wallet and store your passwords in an ecrypted file:
apt-cache show revelation
Gabriel Menini
Linux Registered User #207262
Can be seen as a security hole
Sometimes giving ambiguous info about the command is better than showing the full path and permissions in order to execute it.
However, this can be assumed as a security-through-obscurity approach and some people may not like it.
Take ssh login for example. If you don't type the correct username & password you won't get access to the remote box. If you match the user but the password is still wrong, the remote dæmon won't let you know that _only_ the password was incorrect.
I've found some powerful bash shells over there (say Ubuntu and OpenSUSE) that suggests you the package where the 'command not found' can be found, if not installed.
User-friendly: sure! Safe: not so sure....
Gabriel Menini
Linux Registered User #207262
I don't think you're right.
I don't think you're right. This information (what package to get the command) can so simply be found looking for " package" on a search engine on Internet, that it can't be considered as a secret.
So be friendly with million people is definitively more important than assuming a really little security option for some rare cases.
How about Debian squeeze?
So Ubuntu does this - anyone know if there's similar functionality in squeeze (that needs to be enabled) because it doesn't do it for me at the moment?
Another related usefull bash feature
bash has built-in command called shopt, that can do similar things, like auto correction of directory names (on cd command):
shopt -s cdspellYou can read more about shopt here.
--
My blog: http://frishit.wordpress.com
Is this default in other distributions
Sounds like a great feature, good job openSUSE for enabling it by default.
Does anyone know if Fedora or Ubuntu enable similar behavior by default?
Very useful :-)
Ubuntu has for a long time
a couple of responses have described mis-spelling responses, but Ubuntu goes a step further. If you properly spell the command, but the package is not installed, BASH will tell you how to install the package so the command will be available.
Ubuntu does.
Ubuntu does.
ubuntu@karmic:~$ pascal
No command 'pascal' found, did you mean:
Command 'pscal' from package 'xcal' (universe)
pascal: command not found
Ubuntu does...
...and it is REALLY useful as it even copes with mis-spellings:
$ pascalNo command 'pascal' found, did you mean:
Command 'pscal' from package 'xcal' (universe)
pascal: command not found
$ pling
No command 'pling' found, did you mean:
Command 'plink' from package 'putty-tools' (universe)
Command 'ping' from package 'inetutils-ping' (universe)
Command 'ping' from package 'iputils-ping' (main)
pling: command not found
$
so even with my occasionally rubbish typing I get what I need and a good idea of what to install to enable it.
--
Smotsie
Dad.husband.linux-loving-geek.radio-presenter.eco-geek