2

I've looked for the greater part of two hours trying to see if I could find a way to redirect the output of a bash script to the line that called the bash script.

The best example I can use to describe what I'm looking for is the Completion function that gets executed when one presses [TAB]:

$ech[tab] #--> $echo  

I should note that the #--> was supposed to represent how the completion finished off the word "echo".

The closest thing I was able to find was setting certain options to "echo" so that \b\b can be read, and stdout can update the same line. But this is not what I'm looking for. I'd like to be able to output directly to either current, or next line within the console input. Is this even possible from bash script?

Edit:

Thanks to all who responded. I feel like I should update my original question, and possibly even change the question title itself.

The scope of my question changed in the following way: this no longer is a question about what I can or can't accomplish via scripting alone. My original goal was to emulate the Completion "function," which I've come to learn is actually a built-in bash command.

It seems that the specific library that I should put attention to (in order to even begin trying to emulate bash's tab-completion command) is the Readline library. bash-completion itself was implemented in C(++?).

In any case, thanks again for the insightful responses, and if anyone has tips beyond what is stated in the above article (maybe from personally using the Readline, or Completion libraries), I look forward to reading your comments.

  • 1
    Notwithstanding that all command in console should be ended by Return which mean new line you can operate the some terminal operation command (tput for example) to read current cursor position than move cursor (after script execution) back to remembered coordinates. – Costas Feb 15 '15 at 11:59
  • 1
    I don't understand what you're trying to do here. Are you trying to modify the script file? Or are you assuming that the script's output is a terminal? What do you want to do if the script isn't called directly from an interactive shell in a terminal? This sounds like an XY problem; there's a good chance that you should be writing a function and perhaps binding it to a key. What are you trying to achieve? – Gilles Feb 15 '15 at 22:12
  • Do you want to emulate the completion library or make use of it to give custom completions? As Gilles says, this sounds like an XY problem, tell us what you trying to do, and see if we can figure out a solution. – icarus Nov 20 '16 at 6:16
1

There are two ways I can interpret this question - it would seem you either want to overwrite what was already written to the terminal with something different - which is fairly easily done - or else you want to programmatically feed the current interactive shell input.

The thing is - these questions ultimately mean two very different things. A mistake a lot of people make (one I certainly did anyway - repeatedly) is to equate the visual characters printed on the terminal screen with the input typed at the keyboard as one and the same. In truth, though, the keyboard is a much more simple thing to handle than is the output on screen - there's a lot of work going on between the two to transform the former into the latter. The printout on the terminal is a convenience - and it often lies.

If you want to feed input to the shell, then writing to the screen is probably not going to help you. You can do it of course, emitting a standard VT102+ escape sequence for moving up a terminal line could look like:

printf '\033[A'

...but if you do that it won't look like much happened - and this is because the shell isn't reading that - it's writing to the same place you are. You can do:

printf '\033[A'; cat

...to actually see what it does, because cat will prevent the shell from immediately drawing a new prompt. You can (probably) add a numeric parameter between the [ bracket and the A for multiple lines. You can go down with B, left with D, and right with C. Saving the output of tput as called with the termcap sequences you can find in man termcap to named variables is usually the way people go though - and rightly so. Terminals are funny things.

If you want to have some real fun you can try:

stty raw isig -echoctl; cat >/dev/null

On an xterm-compatible terminal emulator (provided stty supports -echoctl - but if it doesn't you shouldn't need it anyway) that should basically allow you to walk all over your terminal screen with the arrow keys and type over any of the text there. But none of that matters much because you're overwriting the display - the shell doesn't care for that at all.

If you want to affect a shell you have to talk to its stdin. An interactive shell will typically not listen much to what you have to say on that front unless you tell it up-front - when you call it. Otherwise it's just going to listen to the keyboard - that's what it's for (or rather, more correctly, the keyboard is its stdin). But you do have options.

A good way to script an interactive shell's input is to delay it. For example, you can get a dummy prompt - one which will do basically nothing but accept keyboard input and echo that to stderr like:

sh -niv 2>&1 >/dev/null | ...

It needn't be your /bin/sh either - it will work fine for bash or whatever. bash will do all of the typical readline stuff - even command history and $PS1 - but it will execute -nothing and -verbosely print all input to the pipe. You can then channel it however you like - maybe over another pipe to another bash after filtering a little.

You can do a lot of these kinds of things - but you can't go back in time. The last command is already over once your script starts. You can't change it - but you can arrange it so you can filter future commands.

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.