How can I set the cursor to the beginning of line in a bash script. It should have the same behavior as pressing Ctrl-a.
I tried something like this echo -e "\e[H" but it didn't work.
Here is what I'm trying to do. Let's say I have a command that I want to perform an action on it (doesn't matter what) before executing it. So I associated a Key (using bind -x ) to a function that will perform that action. However, before executing that action, I need to place the cursor to the beginning of that command (as if pressed Ctrl-a)
While Deanie's answer of
echo -ne "\r"
is correct, I found I had to ensure that my hash bang was correct:
#!/bin/bash
NOT
#!/bin/sh
Wouldn't it just be
echo -ne "\r"
Sorry, forgot to suppress the newline.
Let say want bind the /some/path to shift-alt-W and want move to the beginning of the line:
bind '"\eW":"/some/path\C-a"'
Pressing the shift-alt-w will enter the /some/path into the terminal, and the \C-A cause to move to the beginning of the line so you can type cd before the /some/path.
Related
First you may refer to this great post here: Bash bind for better understanding what I am trying to achieve.
I want to achieve that when I hit the enter then update the shell prompt dynamically, now I already had is:
__update_shell_prompt () {
# according what I had done in the terminal regenerate the new shell prompt
# new_shell_prompt
export PS1=$new_shell_prompt
}
bind '"\C-M":"\n__update_shell_prompt\n"'
It works as expected, just after each command I executed it would echo the text __update_shell_prompt also, like:
I also tried to use the bind with the -x option like this:
bind -x '"\C-M":"\n__update_shell_prompt\n"''
Then it doesn't respect the \n, so it totally doesn't work, if I remove the \n, it still doesn't work, and bring another serious problem in, the command I tried to execute just remain in the screen and never would get executed, like so: all commands just get stuck there...
So:
How can I make that don't echo the command text...
If this is not the right way to achieve this(dynamically update shell prompt upon enter hitting), then how should I do this?
First thanks #Charles Duffy, I followed his suggestion and used the tput.
The solution is simple, use tput cup to move the cursor up, then use tput el to delete that line, as below:
# Get the current cursor coordinate.
IFS=';' read -sdR -p $'\E[6n' ROW COL; local current_row=`echo "${ROW#*[}"`
# Move the cursor up then delete that line
tput cup $((current_row-2)) 0 && tput el
Tips:
To prevent the potential commands history pollution, you can put export HISTCONTROL=ignorespace into your ~/.bash_profile or ~/.bashrc;
Then invoke the command with prefixed space.
The problem I used this scenario to solve can be referred here: docker-machine PR #4127.
Consider the following minimised Bash Script:
echo Enter your name:
read NAME
echo $NAME
Now if I run the script and enter a name and want to navigate through my input with my arrow keys, [[D^ characters are getting returned.
How would you rewrite that script to cater for such behaviour, i.e. let me navigate with keys instead of winning an ASCII contest ?
These character sequences are the way that the terminal communicates that "cursor left" has been pressed. If the program receiving it does not interpret it as such and instead just displays them (after filtering the escape character), that's what you get.
Luckily for you, the read command of bash has the option -e to enable use of Readline for reading in the line. Readline performs all that handling (as it does on the normal bash command input).
Thanks to Andreas and some due dilligence with a search engine, I was able to rewrite my script:
echo Enter your name:
read -e NAME
echo $NAME
Now navigating through the input with arrow keys, works like a expected.
Here you can learn more about the read builtin command.
I am trying to edit my .bashrc file with a custom function to launch xwin. I want it to be able to open in multiple windows, so I decided to make a function that accepts 1 parameter: the display number. Here is my code:
function test(){
a=$(($1-0))
"xinit -- :$a -multiwindow -clipboard &"
}
The reason why I created a variable "a" to hold the input is because I suspected that the input was being read in as a string and not a number. I was hoping that taking the step where I subtract the input by 0 would convert the string into an integer, but I'm not actually sure if it will or not. Now, when I call
test 0
I am given the error
-bash: xinit -- :0 -multiwindow -clipboard &: command not found
How can I fix this? Thanks!
Because the entire quoted command is acting as the command itself:
$ "ls"
a b c
$ "ls -1"
-bash: ls -1: command not found
Get rid of the double quotation marks surrounding your xinit:
xinit -- ":$a" -multiwindow -clipboard &
In addition to the double-quotes bishop pointed out, there are several other problems with this function:
test is a standard, and very important, command. Do not redefine it! If you do, you risk having some script (or sourced file, or whatever) run:
if test $num -eq 5; then ...
Which will fire off xinit on some random window number, then continue the script as if $num was equal to 5 (whether or not it actually is). This way lies madness.
As chepner pointed out in a comment, bash doesn't really have an integer type. To it, an integer is just a string that happens to contain only digits (and maybe a "-" at the front), so converting to integer is a non-opertation. But what you might want to do is check whether the parameter got left off. You can either check whether $1 is empty (e.g. if [[ -z "$1" ]]; then echo "Usage: ..." >&2 etc), or supply a default value with e.g. ${1:-0} (in this case, "0" is used as the default).
Finally, don't use the function keyword. bash tolerates it, but it's nonstandard and doesn't do anything useful.
So, here's what I get as the cleaned-up version of the function:
launchxwin() {
xinit -- ":${1:-0}" -multiwindow -clipboard &
}
That happens because bash interprets everything inside quotes as a String. A command is an array of strings which the first element is a binary file or a internal shell command. Subsequent strings in the array are taken as argument.
When you type:
"xinit -- :$a -multiwindow -clipboard &"
the shell thinks that everything you wrote is a command. Depending on the command/program you ran all the rest of the arguments can be a single string. But mostly you use quotes only if you are passing a argument that has spaces inside like:
mkdir "My Documents"
That creates a single directory named My Documents. Also, you could escape spaces like this.
mkdir My\ Documents
But remember, "$" is a special character like "\". It gets interpreted by the shell as a variable. "$a" will be substituted by its value before executing. If you use a simple quote ('$a') it will not be interpreted by the shell.
Also, "&" is a special character that executes the command in background. You should probably pass it outside the quotes also.
Consider the following minimised Bash Script:
echo Enter your name:
read NAME
echo $NAME
Now if I run the script and enter a name and want to navigate through my input with my arrow keys, [[D^ characters are getting returned.
How would you rewrite that script to cater for such behaviour, i.e. let me navigate with keys instead of winning an ASCII contest ?
These character sequences are the way that the terminal communicates that "cursor left" has been pressed. If the program receiving it does not interpret it as such and instead just displays them (after filtering the escape character), that's what you get.
Luckily for you, the read command of bash has the option -e to enable use of Readline for reading in the line. Readline performs all that handling (as it does on the normal bash command input).
Thanks to Andreas and some due dilligence with a search engine, I was able to rewrite my script:
echo Enter your name:
read -e NAME
echo $NAME
Now navigating through the input with arrow keys, works like a expected.
Here you can learn more about the read builtin command.
In Bash, typing for example !make followed by Enter will recall and also execute the last command that starts with "make" in the history.
What I'd like is to just recall that command, but not evaluate it right away until I hit Enter again, to allow me to look at it, or edit it if needed.
Is there a way to do that in Bash?
You can use CTRL+p to get the previous command
You can also use CRL+r to reverse search for a command in your history.
The p modifier after any history expansion prints the result to the command line for further editing, rather than executing it.
$ echo foo
foo
$ !!:p
$ echo foo
^
|
cursor remains here
You can expand history on the current line using the history-expand-line key (M-^).
The M modifier key is usually mapped to Alt.
$ !make
AltShift6
$ make -C mydir
if your last make command was make -C mydir. You can then edit the command line in place.
Alternatively, you can scroll through history as outlined in other answers.