📜 ⬆️ ⬇️

Guessing thoughts and executing non-existent commands using bash

In Debian, a patch has been added to bash, thanks to which the user can write his own function to be performed if the command entered by the user is missing. In Ubuntu, this feature uses the command-not-found tooltip, which significantly slows down the work, while you can find more interesting and useful possibilities for using this mechanism, leaving the search for the package to specialized programs. I will share my experience.

Our unit has a special network for test servers and virtual machines: 192.168.20.0/24, and very often you have to type commands like ssh user@192.168.20.xx , and only the last digit is different in the commands. For a limited number of servers, you must specify a different username . Less often, you have to go to servers on other subnets (within 192.168.0.0/16); sometimes clients also give us access to their systems so that we can diagnose their problem and solve it on the spot.

As follows from the previous paragraph, very often commands like this are typed:
  ssh ordinary_user@192.168.20.xx
 ssh special_user@192.168.xx.yy
 ssh third_user@ww.xx.yy.zz 


There is a natural desire to reduce and optimize this process. When there were few servers, I created a lot of clever aliases like the following:
  alias 123 = 'ssh user@192.168.20.123' 

')
However, I soon realized that maintaining a list of fifty alias was not a true unix way, and thought about alternatives. I remembered the experiences of webmasters of the era of web 1.0 on using 404 errors to display a page with the necessary content, thought about how bash intercepts a call from an unknown command and replaces it with a team searching for the right package ... As a result of a cursory examination of the command-not-found package, it was found out that the command_not_found_handle function is used. It takes a command entered by the user as an argument, performs some actions and returns 127 if nothing can be done (in this case, bash displays a standard error message), or any other number if something worked out.

The rest turned out to be a matter of technique. A function has been added to ~/.bashrc :
  command_not_found_handle () {
     if [[!  "$ 1"]];  then
         return 127
     fi

     n = "$ 1"

     if echo $ n |  perl -ne 'exit (/ ^ ([1-9] | [1-9] \ d | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]) $ /? 0 :one)' ;  then
         ip = 192.168.20. $ n
     elif echo $ n |  perl -ne 'exit (/ ^ ([1-9] | [1-9] \ d | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]) \ (([ 1-9] | [1-9] \ d | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]) $ /? 0: 1) ';  then
         ip = 192.168. $ n
     elif echo $ n |  perl -ne 'exit (/ ^ ([1-9] | [1-9] \ d | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]) \ (([ 1-9] | [1-9] \ d | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]) \. ([1-9] | [1-9] \ d | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]) \. ([1-9] | [1-9] \ d | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]) $ /? 0: 1) ';  then
         ip = $ n
     else
         return 127
     fi

     ssh $ ip
 }


Any entered number from 1 to 255 is converted to the ssh 192.168.20. command ssh 192.168.20. . Number; two numbers - in ssh 192.168.. . number; any entered IP address is converted to ssh IP- . In all other cases, the message "command not found" is simply displayed.

Since a rather complicated regular expression is used, it was necessary to use perl to process it. There was also a variant with grep -qP , but the experimental -P option (extended support for perl-regular regular expressions) is not included in grep in all distributions (for example, it is not in Ubuntu 8.04, but already in 8.10).

For all hosts in the 20 network to substitute the common user name ordinary_user, and for selected hosts - special names, in ~ / .ssh / config I added lines (common parameters for all hosts preceded by the Host * construct should be at the bottom of the list):
  Host 192.168.20.251
 User special_user1

 Host 192.168.20.252
 User special_user2

 Host 192.168.20.254
 User special_user3

 Host *
 User ordinary_user 


Unfortunately, I was not able to force this function to process the command line parameters too: only the first positional parameter is passed to the command_not_found_handle function, the rest are not available. Therefore, for each non-standard host, you will have to either write the full version of the command with all the parameters, or specify the server settings in ~ / .ssh / config, like the ones above. There are other shortcomings in the implementation, discussed, in particular, on the site smylers hates software .

However, even with such limitations, new exciting opportunities are opening up. I think that the application proposed by me is not the only one, and this post is not the last one on this topic.

PS bonus for those who read up to this point: a library of regular expressions perl , where I found a regexp to check the string for IP address compliance.

Source: https://habr.com/ru/post/44788/


All Articles