4

I'm trying to write a Python or Bash script that outputs a bash command directly to the command line (i.e. as if I just typed it and could then hit enter to execute it).

How can I output the command in this fashion?

RCCola
  • 373
  • 1
  • 12
  • If you use Python, you could do it where you execute the command while still in Python. I found this http://stackoverflow.com/questions/4760215/running-shell-command-from-python-and-capturing-the-output with a quick search, so you should be able to find enough information about how to do it. – Rob Watts Apr 09 '14 at 02:19
  • 1
    Thanks, but I want it to be output to the bash command line so I can execute it by hitting enter if I choose to execute it. I'm also aware of how to do what you're suggesting in bash. I want the command to be output to the command line, not executed. – RCCola Apr 09 '14 at 02:39
  • Why does it need to be on the command line? Why not just have the program print the command and wait for user input before running the command (which would allow you to cancel the program if you didn't want to run the command)? – Rob Watts Apr 09 '14 at 02:43
  • I basically want to recreate the experience of selecting a command like in reverse search. I want that command to then be output so that it can be executed in bash. – RCCola Apr 09 '14 at 02:49
  • 1
    For those familiar with `zsh`, he's looking for the feature provided by `print -z`. – chepner Apr 09 '14 at 12:08
  • Yeah exactly like that, perfect example. – RCCola Apr 09 '14 at 13:34
  • 1
    You will want to read [BashFAQ/050](http://mywiki.wooledge.org/BashFAQ/050). – Adrian Frühwirth Apr 09 '14 at 14:28
  • If what you're **really** trying to do is set up a completion handler, by the way, you should say that rather than asking this different, more complicated question. (Completion handlers can invoke external commands, but are not external commands themselves, and so can do things external scripts cannot). – Charles Duffy Apr 09 '14 at 14:36

4 Answers4

3

I don't think this is possible in bash. However, a reasonable subset of the functionality of the prompt can be simulated in bash 4 or later by using the read builtin and immediately executing the input with eval:

$ read -ei "ls -l"; eval "$REPLY"

Implicit line continuation is not available, such as if you end the line with a |; you'll need to explicitly provide the line-continuation character, and the next line will also have the initial text inserted, so you'd have to clear the line before continuing.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • `-i`? Was that intended to be `-r`? – William Pursell Apr 09 '14 at 13:08
  • 2
    No; `-i` is used with `-e` to put a default value on the line, which can be edited using `readline` before accepting the line. I debated whether to include `-r` in this example as well, and decided against it to allow explicit line continuation. – chepner Apr 09 '14 at 13:18
  • I get the -i option on my linux box, but not on my Mac :/ only options on mac is: `code read: usage: read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]` – RCCola Apr 09 '14 at 13:38
  • 2
    As I said in the answer, this requires version 4 or later; Mac OS X ships with 3.2, but you can install the latest version with something like Homebrew. – chepner Apr 09 '14 at 13:47
  • `GNU bash, version 4.2.45(2)-release (i386-apple-darwin13.0.0)` my bash version looks fine though? – RCCola Apr 09 '14 at 16:20
  • 2
    Perhaps your login shell is `/usr/local/bin/bash` (or some alternate path to `bash` 4.2), and you see the error from a script that uses `/bin/bash`? The usage string you posted is from 3.2. – chepner Apr 09 '14 at 16:37
0

With BASH you can easily do that using the select builtin command. Here there is a good example to start: http://linux.die.net/Bash-Beginners-Guide/sect_09_06.html

Magno Torres
  • 530
  • 4
  • 7
  • 1
    Could you give an example? It doesn't look like this is what I want from the link you sent. – RCCola Apr 09 '14 at 03:12
  • select command in "ls -l" "echo foo" "df"; do echo "Command: $command, press to execute or to stop"; read; $command; done – Magno Torres Apr 09 '14 at 03:24
  • Still not what I'm looking for. I want the command to just be written out directly to the bash command line. – RCCola Apr 09 '14 at 03:39
0

vim-slime accomplishes something similar by going through screen or tmux. Here's a proof of concept in Bash for running under tmux:

print_to_cmd_line() {
    printf '%s' "$*" | tmux load-buffer -
    tmux paste-buffer -d
}
Michael Kropat
  • 14,557
  • 12
  • 70
  • 91
0
cmd=( ls -l "hello world" )                # given an array as input
printf '%q ' -v cmd_quoted "${cmd[@]}"     # transform it to an eval-safe string
echo "Run the following: $cmd_quoted"      # ...which can then be run by the user

One way to use this from Python is to pipe content to bash (you could of course also be running the relevant bash script via subprocess.Popen()):

#!/usr/bin/env python
import sys 
cmd=['ls', '-l', 'hello world']
for element in cmd:
  sys.stdout.write('%s\0' % element)

...and in bash, to read that NUL-delimited input and write an eval-safe command:

#!/usr/bin/bash
arr=()
while IFS= read -r -d '' entry
  arr+=( "$entry" )
done
printf '%q ' "${arr[@]}"
printf '\n'

...then, to tie them together:

./python-gen-cmd | ./bash-gen-cmd

...will give you a safe command on stdout, ready to copy-and-paste or send over a SSH connection. This works even when your commands contain non-printable characters or similar oddness.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441