Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Sometimes I'm working on a new (ubuntu) box and I type git and am alerted:

The program 'git' is currently not installed.  You can install it by typing:
apt-get install git-core

If that happens I know that I can grab the last line by doing something like:

!! 2>&1 | tail -n 1

But how could I execute the result of that (apt-get install git-core) most easily?

I realize I could do

`!! 2>&1 | tail -n 1`

but is there also a way to actually pipe the output and have it be run? This does not seem to work:

!! 2>&1 | tail -n 1 | sh

Also the 2>&1 part is a little cumbersome so I would be curious if there is an easier way to make that happen as well.

Edit

It would also be acceptable to save this to a variable somehow, and then execute the variable:

!! 2>&1 | tail -n 1 | (store as $mycmd)
$mycmd

But I'm not sure I know a way to pipe stdout into a variable either, at least not with the variable being on the right side of the command.

share|improve this question

4 Answers 4

up vote 6 down vote accepted

When you type command that don't exists in your system bash runs function command_not_found_handle(). In this function there is a call to /usr/lib/command-not-found script that prints messages.

Ubuntu 12.04

My first guess to change source of this script to print messages to stdout instead stderr, but when I was reading source of script I found that you can configure it to just ask you if you want to install missing package.

If you export variable COMMAND_NOT_FOUND_INSTALL_PROMPT you will be asked to install missing package:

pbm@ubuntu:~$ git
The program 'git' is currently not installed.  You can install it by typing:
sudo apt-get install git
pbm@ubuntu:~$ export COMMAND_NOT_FOUND_INSTALL_PROMPT=""
pbm@ubuntu:~$ git
The program 'git' is currently not installed.  You can install it by typing:
sudo apt-get install git
Do you want to install it? (N/y)y
sudo apt-get install git
[sudo] password for pbm: 

Older versions of Ubuntu

Unfortunately there is no COMMAND_NOT_FOUND_INSTALL_PROMPT so I can find few other options:

1) Install package from 12.04 - it shouldn't be the problem - it's only few scripts in Python so it should work (untested!).

2) Change stderr to stdout. To do it edit file /usr/lib/python2.7/dist-packages/CommandNotFound/CommandNotFound.py and change stderr to stdout in lines 237 and 240.

After that you can use it in this way:

pbm@ubuntu:~$ git
The program 'git' is currently not installed.  You can install it by typing:
sudo apt-get install git
pbm@ubuntu:~$ `git`
//Installation begins

If you add -y option to apt-get command in lines 237 and 240 you could also use syntax !! | sh.

3) You can also modify this script from line 242 in this way:

print >> sys.stderr, _("You can install it by typing:")
f = open("%s/.install-missing" % os.path.expanduser('~'),'w')
print >> sys.stderr, "sudo apt-get install %s" % packages[0][0]
print >> f, "sudo apt-get install %s" % packages[0][0]
f.close()

In this way you will get your command in file ~/.install-missing, so you may create alias:

alias im="chmod +x ~/.install-missing; ~/.install-missing"

If you call im package will be installed.

share|improve this answer
    
Hmm, this looked really good but actually doesn't seem to work on 11.10 oneiric, /usr/lib/command-not-found but has no reference to COMMAND_NOT_FOUND_INSTALL_PROMPT - thoughts? –  cwd Apr 5 '12 at 14:01
    
Ok, looks like this is a feature that will be part of 12.04 precise, (package-import.ubuntu.com/diffs/command-not-found) . I guess I still need a solution for earlier versions. –  cwd Apr 5 '12 at 14:18
    
@cwd: I updated my answer... –  pbm Apr 5 '12 at 16:49

You were on the right track with:

!! 2>&1 | tail -n 1 | sh

...but you're missing an option to sh. Consider:

!! 2>&1 | tail -n 1 | sh -s

And since you probably need root access to run apt-get, consider:

!! 2>&1 | tail -n 1 | sudo sh -s
share|improve this answer
    
This doesn't work. sh and sh -s does same thing, atleast in this case. –  Deepak Mittal Apr 6 '12 at 5:17

You can do something like this:

!! 2>&1 | tail -n 1 > /tmp/cmd; bash /tmp/cmd; rm /tmp/cmd

Interactive programs don't seem to work well with piping because it expects an input, 'Y' in this case, but the stdin file descriptor is closed as soon as the first command gets over.

share|improve this answer

You can use a variable, eval and command substitution I believe (though I'm not sure how safe this all would be):

TEST_VAR=$(!! 2>&1 | tail -n 1); eval $TEST_VAR

I'm willing to be proved wrong with the above. I'm testing this on a Red Hat machine with an echo command rather than that bash completion auto suggest but the principle should be the same.

At the end of the day, it would be quicker to just type aptitude install git...

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.