How to modify every bash command before execution? - bash

Is there a way to modify every command that is entered at the bash prompt with a script/hook?
In my ideal world, the script would fire after the user has entered the command but BEFORE the Enter key is pressed. It would get the command string as a parameter, modifiy it and hand it over to bash for executing (so everything would happen transparently).
I would use this hook for some company-specific substitutions which cannot be done using aliases, but above all I'm interested if this can be done.
I know of some hacks to do something with the last command after it has been executed (trap 'function' DEBUG and the like) as there are a lot of questions concerning that scenario but this is of no help here.
Thanks and kind regards!

What you want is a kind of command completion -- it seems to me.
There is a lot behind bash line editing: bindable readline commands, or command completion and command substitution.
First off you can write write and compile your own bash builtins:
http://www.drdobbs.com/shell-corner-bash-dynamically-loadable-b/199102950
Next, you can alter bash through what people call edit line or readline:
Start here maybe:
http://www.math.utah.edu/docs/info/features_7.html
http://www.gnu.org/software/bash/manual/html_node/Command-Line-Editing.html

Related

Programmatically/script to run zsh command

As part of a bigger script I'm using print -z ls to have zsh's input buffer show the ls command. This requires me to manually press enter to actually execute the command. Is there a way to have ZSH execute the command?
To clarify, the objective is to have a command run, keep it in history, and in case another command is running it shouldn't run in parallel or something like that.
The solution I've found is:
python -c "import fcntl, sys, termios; fcntl.ioctl(sys.stdin, termios.TIOCSTI, '\n');
I'm not sure why, but sometimes you might need to repeat the command 2 times for the actual command to be executed. In my case this is happening because I send a process to the background, although this still doesn't make much sense because that process is sending a signal back to the original shell (triggering a trap) which actually calls this code.
In case anyone is interested, this was my goal:
https://gist.github.com/alexmipego/89c59a5e3abe34faeaee0b07b23b56eb

How to test external tab completion script in Ruby

So say I have an external command, fart, that supports tab completion for its subcommands. When you type fart <\tab><\tab> in the command line, it prints out something like
$ > fart █
do some things here
or other stuff there
however, if you type fart <\enter>, it prints the help text
fart is a tool for doing things and stuff
Usage: fart <command>
Commands:
init Initialize a new something or other
status Report the status of the thing
version Show the fart version information
I want to test that the tab completion works via an integration test suite in Ruby. When I tell exec to execute fart \t\t, I get the help output, not the autocomplete output. How can I get exec to not terminate the shell command with a newline so that I can assert the autocompletion output?
You shouldn't fa^M^M exec the thing. It doesn't work like this. You need to interact with a PTY. Basically spawn a shell in a PTY, then send keys like you would do interactively.
Alternatively you could write expect scripts and use the expect utility found in most linux distros.
Auto-completion is a shell function, not a program function. When you hit tab, bash or some other shell is looking for completion definitions and uses them to show you the available options. It is not executing the program in any way.

Bash script calls vi for manual editing, then script resumes?

I wrote a script that creates a backup of a text file, and a second script that verifies some syntax in text file using SED.
In the middle, there is a manual process: Users edit the original file adding some strings. This process must remain manual.
I would like to merge my two scripts so the backup is created, vi is open for the user, when the user is done editing the file, the script resumes doing the syntax verification.
I am learning by doing, but really do not know how to code the "open vi, wait for the user to do his editing, take control over and resume with verification" part.
I read there is a function called system (in Perl) that could be used, but my code is in BASH.
Any suggestions on how to get this done in BASH? Thanks!
In bash, each statement is essentially like an implicit call to system (unless it's a builtin shell command) since shell scripts are designed to make it easy to run other programs.
backup some_file.txt
vi some_file.txt # The script blocks until the user exits vi
verify_syntax some_file.txt
The only difference between using vi and a command like ls is that ls will do its thing and exit without user intervention, while vi (or any interactive command) will run until the user explicitly exits.

Bash and readline: how to bind key to a "silent command" of my own in bash?

What I want to do is simple: add a keybinding to one of my program using readline startup file inputrc but, in addition, as my program does not produce any output, I do not want the command name to appear on stdout.
What my problem is:
.inputrc content:
"\e[1;5A":'pipe_send\n'
When I hit ctrl+uparrow, on the command line appears "pipe_send":
[ alexkag#$$$$$:: / ]
$ pipe_send
What I'd like is not having pipe_send appear on the command line, just like the commands provided by readline such as history-search-backward, history-search-forward, etc.
Do you know any way to do that? Maybe shoudn't I use readline? Note: my keybinding must only be visible in bash, not to the whole system.
As mentioned in the comments by gniourf_gniourf the solution is:
bind -x '"\e[1;5A":pipe_send'
bind -x will tell bash to execute a command whenever a certain key is pressed:
-x keyseq:shell-command
Cause shell-command to be executed whenever keyseq is entered. When shell-command is executed, the shell sets the READLINE_LINE variable to the contents of the Readline line buffer and the READLINE_POINT variable to the current location of the insertion point. If the executed command changes the value of READLINE_LINE or READLINE_POINT, those new values will be reflected in the editing state.
\e[1;5A is the terminal code sent for CtrlUp

Can I use what I wrote on the shell (bash, cmd, irb, etc) in a script automatically?

The general idea is pretty simple, I want to make a script for a certain task, I do it in the shell (any shell), and then I want to copy the commands I have used.
If I copy all the stuff in the window, then I have a lot of stuff to delete and to correct. (and is not easy to copy from shell)
Resume: I want to take all the things I wrote...
Is there an easy way to do this easy task?
Update: Partial solution
In bash, the solution is pretty simple, there is a history command, and there are ports of the idea:
IRB: Tweaking IRB
Cmd: Use PowerShell -> Get-History (or use cygwin)
Another Update:
I found that doskey have a parameter history to do this:
cmd: Doskey /history >> history.cmd
Yes, you can use:
history -w filename.sh
This will save your command history to filename.sh. You may need to edit that to keep just the lines at the end that are part of your command sequence.
NOTE: This is a bash command and will not work with all shells.
script may help here. Typing script will throw you into a new shell and save
all input and output to a file called typescript. When you're done with your interaction,
exit the shell. The file typescript is then amenable to grep'ing. For example, you might
grep for your prompt and save the output to the file. If you're a clumsy typist like me, then you may need to do some cleanup work to remove backspaces. There used to be a program that did thisbut I don't seem to find it right now. Here is one I found on the
'net: http://www.cat.pdx.edu/tutors/files/fixts.cpp
This approach is especially useful if you want to track and post on the web an entire interactive session.

Resources