I'm trying to get the prompt reset, forget all the variables and start the prompt from line 1>
I'm aware of the following built-in functions
f(). %% forget all
io:format("\e[H\e[J"). %% "clear screen" and moving cursor to the begin of the line
but when I'm writing the following commands, it does forget all the variables, but it doesn't "reset" the screen, just clear the screen, like clear command in the terminal.
in Linux, I just type reset, but I couldn't find equivalent command or built in function for erlang to do that.
I also tried io:format(os:cmd("reset")). but I received error.
my solution for now is to quit the erlang terminal, and reopen it again, but I'm sure there is much easier ways to do that.
To clear the erl shell
io:format(os:cmd(clear)).
A somewhat tricky way to do it would be to just start a new shell by pressing ctrl-g and then s, c
$ erl
Erlang/OTP 18 [erts-7.3] [source-d2a6d81] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V7.3 (abort with ^G)
1> A = 1.
1
2>
User switch command
--> s
--> c
Eshell V7.3 (abort with ^G)
1> A.
* 1: variable 'A' is unbound
2>
Of course that doesn't clear the screen. You have to use your own console mechanisms for that (I use iTerm on OSX and I just hit cmd-k for that)
Most of the terminals you would use on a Unix-like system support the VT100 hardware-reset escape sequence. You could use that in your program like this:
io:format("\ec").
That is instead of
io:format("\e[H\e[J"). %% "clear screen" and moving cursor to the begin of the line
although it would not hurt to do both. Also, it does not affect your variables, so you would still do
f(). %% forget all
Combining these:
f(). %% forget all
io:format("\ec").
io:format("\e[H\e[J"). %% "clear screen" and moving cursor to the begin of the line
should be what you intended.
As #Brujo Benavides mentioned earlier . The way to do that is to exit the current erl shell and start a new . You can use the halt(). function which is less tricky .
Or do a more thorough clear. This will clear your terminal's buffer:
io:format("\033\143").
Which equals to either of the following shell commands:
printf "\033\143"
tput reset
The latter requires you have ncurses installed.
Related
I typed a very long command on the command line – only to discover that Bash doesn't like embedded single quotes. It is a bare tty and my only way to save this command for running from within a file is to open vim and start typing this very long command again...
Isn't there a shortcut to fire up vim on the text typed on the command line – directly from the command line?
Sure there is. The following command will edit the current command-line in $VISUAL:
C-x C-e
I found the answer for my case here:
First off a warning from #marlar (I made myself a function to protect myself
from this, see below):
Be very careful with this feature. If you cancel the edit, the original
command line will be immediately executed. So if you are editing rm -rf
<forward slash> and invoke the editor and realize you are into something
dangerous and thus cancel the edit, your root file system will be deleted
without further questions asked.
From the OP #Kartik:
The bash man page says:
edit-and-execute-command (C-xC-e)
Invoke an editor on the current command line, and execute the
result as shell commands. Bash attempts to invoke $VISUAL,
$EDITOR, and emacs as the editor, in that order.
And from #Mark E. Haase
If you use Bash's vi mode, the short cut is Esc, V...
I actually also find that doing just v is sufficient to launch vim with the bash
command sitting there.
From #karlicoss:
if your editor is vim, you can use :cq, it makes it exit with non-zero code,
and prevents the command from execution
Because I'm paranoid about the rm -rf command (I once deleted 2Tb of brain
data with that - 10 days into switching to linux... lucky the sysadmin had a
backup... actual quote: "I've never seen anything that stupid in my 20 years
doing this job"... but I digress) I put the following in my vimrc to
immediately comment out the command if I accidentally bring up vim and
reflexively exit:
function! CheckBashEdit()
" if the file matches this highly specific reg exp, comment the line
"(e.g. a file that looks like: /tmp/bash-fc.xxxxxx)
if match(#%, "\/tmp\/bash-fc\.......") != -1
" comment out the command
silent! execute ":%normal! I# "
write
endif
endfunction
" if we ended up in vim by pressing <ESC-v>, put a # at the beggining of
" the line to prevent accidental execution (since bash will execute no
" matter what! Imagine rm -rf <forward slash> was there...)
autocmd BufReadPost * :call CheckBashEdit()
There seems to be quite a lot of information on how to edit and execute a command using your editor using "edit-and-execute-command (C-x C-e)", but what I would like to achieve is take the current shell command, apply certain filtering (using a script) and then return it to prompt for further approval/manual changes before execution. Is this possible with bash?
Latest update based on my experience
The part 0"+y$dd in the following mapping is really something that you should carefully think about and tailor it to your taste/workflow/experience.
For instance, very frequently I've found myself ending up with multiple lines in the buffer, where I only want to execute the one the cursor is on; in this case I can use 0"+y$dd:%d<CR> instead of 0"+y$dd.
And this is just one of the possible scenarios.
Final answer for those who like vim
Set vim as your EDITOR/VISUAL, so that when editing a command line, you will use vim to edit it.
Put au BufEnter /tmp/bash-fc.* nn <Leader>d 0"+y$dd:wq<CR> in your ~/.vimrc file to map Leaderd (which you will rarely use when editing a command) to the action "delete the current line into the + register without the trailing EOL".
you can use either the + or the * register in the mapping above; the ways to paste into the terminal will likely differ; you need the +clipboard option for these registers to be available.
When finished editing a command in the vim editor, hit EscapeLeaderd.
Paste the clipboard into the terminal (this is terminal-dependent).
Original answer
I often need to do the same, and I do it as follows. (I normally use the set -o vi in bash, so points 1 and 2 in the following are different if you use set -o emacs, the default; based on your question it looks like points 1 and 2 are unified in Ctrl+x followed by Ctrl+e, which is harder to type, imho.)
hit Escape to be in normal mode,
hit v to enter the editor to edit the command,
edit the command as I like,
(This is where you ask the question.)
hit Escape0"+y$dd:wq,
Note: 0"+y$, not simply "+yy, as the latter would copy the newline too, and this would result in executing the command upon pasting it in the command line,
paste the clipboard on the command line
how to do this depends on the terminal you are using, I guess; I hit Ctrl+Alt+v in URxvt.
proceed to approval/manual edit.
Clearly this is just a workaround, consisting in copying the edited command into the clipboard before deleting the whole command, so that nothing gets executed upon exiting the editor; however it's the best I can get for myself.
Update
As my EDITOR (and VISUAL) is equal to vim, when I edit the command, I edit it in vim.
In this respect, I have noticed that the buffer is named /tmp/bash-fc.random, where random is a 6-characters alphanumeric random string.
This gives space to a lot of possiblities, if you use vim as your editor, as you can define some mapping in your .vimrc to execute the whole sequence Escape0"+y$dd:wq. For instance, one command that you'd rarely use when editing a command line is Leaderd; therefore you can put the following mapping in your .vimrc file
au BufEnter /tmp/bash-fc.* nn <Leader>d 0"+y$dd:wq<CR>
so that step 4 in the above recipe becomes
hit EscapeLeaderd
It's not possible to do that in Bash/readline but it's possible in zsh
using edit-command-line command:
darkstar% autoload edit-command-line; zle -N edit-command-line
darkstar% bindkey "^X^E" edit-command-line
Now press Control-x Control-e to open your editor, edit line, leave the editor - you will see the updated command line but it will not be executed automatically.
Now that I think about it, maybe a variation of what #kenorb suggested in a comment is the best workaround (as it seems no solution exists), if we want to stick to bash.
What you can do is prepend a # (the comment character in bash) to the command, rather than echo. Then when you exit the editor, the command will be ineffective, and you will only have to press arrow up (or k, if you use set -o vi), remove the # and confirming.
Note that this strategy adds just a few keystrokes, so it can be fairly efficient, depending on your typing level.
These pieces might get you closer:
a) replace the the normal binding for newline newline (ctrl-M)
bind -x '"\C-M":date"
b) grab the current line from the history using !#
replace date with whatever script you want.
c) edit manually
d) if necessary, somehow tie in !!:p which prints the new command to the command line but does not execute it, thus letting you manually edit it.
e) using ctrl-J submit edited command rather than a newline
or they might not ....
There is an option in bash to modify command from history without executing it. I'm not sure it it's possible to use script for this, doesn't seem to be likely. Although, you can make modifications using history modifiers.
Enable option histverify to prevent execution of modified command
Use chain of modifiers to change last command
Use "!!" to put your result to command line for final edit
Here is how it looks:
$ shopt -s histverify
$ ls *.sh
script1.sh script2.sh script3.sh script-return.sh
$ !!:s/*/script1/:p
ls script1.sh
$ !!:s/1/2/:p
ls script2.sh
$ !!
$ ls script2.sh
script2.sh
I'd like to point you to the Composure framework for Bash (I'm not affiliated with it): https://github.com/erichs/composure
It provides draft and revise functions that sound like they could help with what you're trying to do. Here's a (long) quote from the project's readme file:
Composure helps by letting you quickly draft simple shell functions,
breaking down your long pipe filters and complex commands into
readable and reusable chunks.
Draft first, ask questions later
Once you've crafted your gem of a command, don't throw it away! Use
draft () and give it a good name. This stores your last command as a
function you can reuse later. Think of it like a rough draft.
$ cat servers.txt
bashful: up
doc: down
up-arrow
$ cat servers.txt | grep down
doc: down
$ draft finddown
$ finddown | mail -s "down server(s)" admin#here.com
Revise, revise, revise!
Now that you've got a minimal shell function, you may want to make it
better through refactoring and revision. Use the revise () command
to revise your shell function in your favorite editor.
generalize functions with input parameters
add or remove functionality
add supporting metadata for documentation
$ revise finddown
finddown ()
{
about finds servers marked 'down' in text file
group admin
cat $1 | grep down
}
$ finddown servers.txt
doc: down
It does not seem possible with a keyboard shortcut, at least:
$ bind -P | grep -e command -e edit
complete-command can be found on "\e!".
edit-and-execute-command can be found on "\C-x\C-e".
emacs-editing-mode is not bound to any keys
possible-command-completions can be found on "\C-x!".
vi-editing-mode is not bound to any keys
This can be done in native bash using readline specifically READLINE_LINE and READLINE_POINT variables. I use this functionality all the time though not through vim, you would need to get the value of $selected from your vim command and if not empty it takes your original line + your input and replaces your original line with the combination without executing. output as a variable
_main() {
selected="$(__coms_select__ "$#")"
origonal_text=$READLINE_LINE READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
}
bind -m emacs-standard -x '"\C-e": _main '
bind -m vi-command -x '"\C-e": _main '
bind -m vi-insert -x '"\C-e": _main '
Edit
Just remembered these two utilities that will let you do this as well.
Vipe allows you to run your editor in the middle of a unix pipeline and edit the data that is being piped between programs.
vp, up, vipe, Neomux (upgrade of nvim terminal) you can do some pretty neat throwing buffers between the terminal and split window.
and Athame (full vim on the command line)
https://github.com/ardagnir/athame
careful with that one though plugins work on the cli and it can get funky if you got tons of plugins
I have some of the console commands I would like to use from Emacs, namely ag. It works great in CMD or Far Manager. However when I use it from Emacs shell or eshell I run into a problem which may be (slight chance, though) ag-specific.
When I run shell and then run ag it returns result (help screen) immediately. If I run it searching for a line in files inside directory as ag needle, it hangs and doesn't return anything.
If I run it as ag needle . it returns result immediately, however missing file names and lines numbers, --color and -nogroup options do not affect the printed result in this case.
When I run it via shell-command it returns the correct result (with file names and line numbers). eshell has the same problem.
What do I need to do to make these commands work in shell and/or eshell ?
It's been noted in the answers to this question that Win32 has issues with subprocess buffering. Is there a way to fix it?
I often have need of a shell while using Emacs. Recently, I have been trying to switch over from shell to eshell, so that I will be able to use the same commands regardless of platform.
One of the first things I would like to do is customize my prompt to match my bash prompt. To do this, I am customizing eshell-prompt-function. The only thing I am still missing is the current command count and the last return code. I can do this in bash by setting PS1 to e.g. \! and $? respectively. I have already tried (eshell/echo "$?") for the latter, but it doesn't work (though it works if I execute the command manually in eshell).
Edit:
An example of what part of my current bash prompt looks like is [~][501:0], where 501 is the current command number (so if I type a command and hit Enter it will show 502), and the 0 is the return code.
This puts the return code into the eshell prompt:
(setq eshell-prompt-function
(lambda ()
(format "[%s][%s] "
(abbreviate-file-name (eshell/pwd))
eshell-last-command-status)))
I couldn't find any simple way to put the latest command number into the prompt—and it might be less than useful, since eshell seems to use a ring for command history, so at some point the counter would be stuck at 128, and all the previous prompts would be inaccurate.
Note that you should also update eshell-prompt-regexp to match anything that eshell-prompt-function could come up with.
I'd like to have a blank line after my bash prompt and before the output on my Mac. It should look like this would:
echo; ls
Can I add a newline to my bash prompt and then go back up one line to wait for user input? Is there something obvious I'm missing?
I know this is old but for someone like me who came across this while googling for it. This is how you do this...
It's actually pretty simple!
Check out this link --> Cursor Movement
Basically to move up N number of lines:
echo -e "\033[<N>A HELLO WORLD\n"
Just change the "< N >" to however many lines you want to go back...
For instance, to move up 5 lines it would be "/033[5A"
To my knowledge this is not possible unless you delve into more low-level stuff like full-screen emulators like curses.
This is a bit of a stab in the dark, but you may be able to use VT102 terminal codes to control the cursor without having to use Curses. The relevant VT102 commands that you'd be interested in all consist of sending ESC, then [, then the specific command parameters.
For instance, to move the cursor up one line, one needs to output:
ESC [ 1 A
0x1B 0x5B 0x31 0x41
Be warned that the VT102 documentation generally uses octal, so keep an ascii table handy if you're using hex.
All of this advice is given without having tested it -- I don't know if VT102 commands can be embedded into your bash prompt, but I thought it might be worth a shot.
Edit: Yeah -- looks like a lot of people use VT102 formatting codes in their bash prompts. To translate my above example into something Bash would recognize, putting:
\e[1A
into your prompt should move the cursor up one line.
This is very possible. If your bash has C-v set as the readline quoted-insert command, you can simply add the following to your ~/.inputrc:
RETURN: "\C-e\C-v\n\C-v\n\n"
This wil make bash (readline, actually) insert two verbatim newlines before a regular interpreted newline. By default, only one is inserted, which is what causes output to start on the line after the prompt.
You can test if C-v is set to quoted-insert by typing it in bash (that's Ctrl+V) followed by e.g. an up arrow. This should print ^[[A or something similar. If it doesn't, you can bind it in ~/.inputrc too:
C-v: quoted-insert
RETURN: "\C-e\C-v\n\C-v\n\n"
~/.inputrc can be created if it doesn't exist. The changes will not take effect in running bashes unless you issue a readline re-read-init-file command (by default on C-x C-r). Be careful though. If you do something wrong, enter will no longer issue commands, and fixing your mistake could prove to be difficult. If you should do something wrong, C-o will by default also accept the line.
Adding a newline followed by moving the cursor back to the regular prompt (like you described) is possible, but will not have the effect you intend. The newline you inserted would simply be overwritten by the application output, since you moved the cursor back in front of it.
This works:
trap echo DEBUG
It doesn't add an extra newline if you hit return at an empty prompt.
The command above will cause a newline to be output for every member of a pipeline or multi-command line such as:
$ echo foo; echo bar
\n
foo
\n
bar
To prevent that so that only one extra newline is output before all command output:
PROMPT_COMMAND='_nl=true'; trap -- '$_nl && [[ $BASH_COMMAND != $PROMPT_COMMAND ]] && echo; _nl=false' DEBUG
The DEBUG trap is performed before each command so before the first command it checks to see if the flag is true and, if so, outputs a newline. Then it sets the flag to false so each command afterwards on the line doesn't trigger an extra newline.
The contents of $PROMPT_COMMAND are executed before the prompt is output so the flag is set to true - ready for the next cycle.
Because pressing enter on an empty command line still triggers the execution of the contents of $PROMPT_COMMAND the test in the trap also checks for those contents as the current command and doesn't perform the echo if they match.
I believe (but haven't tried) if you put '\n\b' in the prompt string it would do that.
In general, if you want to find out the codes to do anything a terminal can do, read the terminfo man page.
In this case, the cursor up one line code can be determined by:
tput cuu1
If you redirect the tput output to a file, you can see what control characters are used.
Bash also supports the PROMPT_COMMAND variable, allowing you to run arbitrary commands before each prompt is issued.