6

(Background: I'm a long-time tcsh user, gradually transitioning to bash, and trying to find equivalents for some useful tcsh-specific features.)

In tcsh, I can define a key binding that executes an external command. For example, given:

bindkey -c ^Gu uptime

I can type "Control-G u" in tcsh, and it will execute the uptime command. I don't have to type Enter, the command doesn't appear in my history, and I can do it in the middle of an input line (I find the latter particularly useful for certain commands).

bash has a similar key binding mechanism via the GNU readline library, with bindings specified in $HOME/.inputrc (or elsewhere). But after reading the info readline documentation, I don't see a way for a key binding to execute an external command.

The closest thing I've figured out is to add something like this to my .inputrc file:

"\C-gu": "uptime\n"

but that doesn't execute the command; rather, it acts as if I had typed uptime followed by the Enter key. The command appears in my history (that's ok), and it works only on an empty line; if I type "echo control-Gu", then it prints uptime rather than executing the command.

Another minor drawback is that the binding affects other commands that use GNU readline, such as the Perl debugger.

Is there a way to simulate the effect of tcsh's bindkey -c in bash, by mapping a key sequence to the execution of a specified external command?

If it matters, I'm using bash 4.2.24 on Ubuntu 12.04 beta 2.

  • As a long-time user of tcsh myself, I'm curious why you are making the transition (other than perhaps the prevalence of bash shells/users) – Levon May 25 '12 at 14:08
  • @Levon: bash is installed by default more commonly than tcsh. bash is better for scripting, and it's nice to use the same language for scripting and interactive use. – Keith Thompson May 25 '12 at 15:13
  • All true .. maybe I'll make the switch eventually too (most of my scripts are actually in Python :-) .. but I see your point for sure. Thanks. – Levon May 25 '12 at 15:22
  • @Levon: And most of my scripts are in Perl, – Keith Thompson May 25 '12 at 15:29
9

Not all bash line editing is controlled from ~/.inputrc; much of it is configured via the bind builtin. In this case, you want something like

bind -x '"\C-gu":uptime'

in your ~/.bashrc.

  • Thanks, that's exactly what I was looking for. This could well be the final nail in the coffin of my tcsh usage. – Keith Thompson Apr 19 '12 at 23:00
  • @KeithThompson Or you could switch to zsh, which does this easily, and more generally nabbed pretty much every feature of tcsh and bash. – Gilles 'SO- stop being evil' Apr 19 '12 at 23:17
2

The other answer provides a solution, that executes the command in a new line. This is useful in some cases, but most of the time my workflow is such, that either I want to

  • Insert the result of an inline execute command in my current command-line (example below)
  • Execute the command truly in the background, no output, no changes in current command line

I use these two principles much more often than the variant @geekosaur showed. Here is an example:

bind '"\C-gd":"\C-u`date +%Y%m%d%H%M`\e\C-e\C-a\C-y\C-e"'

This bind CTRL-gd to kill the existing command (saving it in the cut buffer), insert some shell command, in this case date +%Y%m%d%H%M for a nice timestamp, execute that in-place, and then paste the saved command back to the front of the command-line.

I have a bunch of commands, that output some information from my system, that I regularly use in other command lines, think get_lan_ip, get_gw_ip, get_gw_pubip, get_ns_ip, get_root_block_dev, get_email_addr, get_phone_number and so on. Basically like programmable abbreviations! and all of them one key-stroke behind \C-g away only.

The other very useful use-case for me is calling functions inline, that do not produce output, but silently trigger a background action, like mediaplayer_next, mediaplayer_pause, speakerphone_answer, ... for when I want to trigger things without leaving my terminal, and without losing sight of my current windows contents for even a moment ;)

  • Very cool, I'll have to play with this. A minor point: I'd use $(command) rather than backticks. – Keith Thompson Apr 28 '20 at 21:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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