Say I have a bash window like this:
# cmd 1
output of cmd 1
# cmd 2
output of cmd 2
# (cursor here)
Is it possible to move the cursor (with keyboard only) to previous line, say output of cmd 1, copy some words and paste them to the current cursor position?
I.e. Is there a bash equivalent of the following command in vim:
kkkvllyGp
Thanks
You can use GNU screen.
In a screen session, ctrl+a, esc enters copy mode, where you can move the cursor with the arrow keys, mark start and end points with space, and then paste with ctrl + a, ]
bash has no knowledge of what the terminal displays. If you want to capture the output of cmd 1 and do something with it, you either need to redirect it to a file or capture it in a variable. eg:
cmd 1 > cmd1out.txt
or
CMD1OUT="$(cmd 1)"
Then, once you've captured that output within the shell, you can use it as you like. For example, to execute that output directly as another command, you could do
source cmd1out.txt #if you sent it to a file
or
eval "$CMD1OUT" #if you captured it in a variable
Related
Sorry if I am not giving you enough info, this is my first time posting here.
I am trying to make this in a bash script.
Downloading...............
"run bash commands and when they are done, replace the "Downloading..." text with the text bellow in the same line aka space."
Downloading............... DONE!
go to next line and show
Installing................
"run bash commands again and when they are done, replace the "Installing..." text with the text bellow in the same line aka space."
Installing................ DONE!
I hope you get what I mean. Thanks in advance.
I've tried:
#/bin/bash
tput sc # save cursor
printf "Something that I made up for this string"
sleep 1
tput rc;tput el # rc = restore cursor, el = erase to end of line
printf "Another message for testing"
sleep 1
tput rc;tput el
printf "Yet another one"
sleep 1
tput rc;tput el
But it doesn't make new lines, it just uses one line to show all text.
I'm assuming you pulled the tput code from somewhere, and I'm guessing that 'somewhere' also explained that tput is being used to overwrite the same line multiple times (as your script actually does).
From your description it doesn't sound like you need to overwrite any lines so using tput is the wrong solution.
If I understand your description correctly you should be able to do everything you want with some (relatively) simple printf commands, eg:
printf "Downloading .... " # no '\n' in the output so cursor remains at end of current line
# run your bash commands here
printf "DONE!\n" # append to end of current line and then add a new line (\n)
printf "Installing .... " # no '\n' in the output so cursor remains at end of current line
# run more bash commands here
printf "DONE!\n" # append to end of the current line and then add a new line (\n)
Keep in mind that if any of your 'bash commands' generate any output then the cursor will be moved (probably to a new line) thus messing up your output. Net result is that you'll need to make sure your 'bash commands' do not generate any output to stdout/stderr (alternatively, make sure all output - stdout/stderr - is redirected to files).
If your requirement is to have the 'bash commands' send output to the terminal then you may need to go back to using tput ... but that's going to depend on exactly how you want the output to appear.
NOTE: If this (above) does not meet your requirement then please update the question with more details.
I'm searching for the couple of shortcuts to allow to write multilines commands in the terminal.
I know it exist, I used it many times, but I can't remberber them, and I don't find them in google...
The behavior it have:
Once in the middle of a line, it will "delete" the right part, and when we press the Enter button, it don't execute the command, but go to a new line (that start with '>' if I well remember).
When we are done, we press the second shortcut, and it paste the part that where deleted before, and the Enter key behavior come back as the original.
(I tought it was something like Ctrl+j / ctrl+f, but it's not, I also tried many combination but never succeed)
Hoping you remember them, you'll make my day. Thanks!
Edit for a better understanding:
On a command like this (a call to a ros service, providing arguments):
rosservice call /operatorshift/updateProgramSteps "category: ''
name: ''
steps:
- command: ''
args: ''
othersarg ''"
The steps argument is an array, and I want to provide more than one step, without deleting and rewriting the next lines.
The behavior is as follow:
I move my cursor at the end of the 5th line (args: '' [HERE]), and I press the first shortcut. The command would look like:
rosservice call /operatorshift/updateProgramSteps "category: ''
name: ''
steps:
- command: ''
args: ''
and I press "enter", not to execute the command, but to add a new line (and the '>' character appear on the left of my cursor, instead of my computer's name). I can write my other "step", pressing "enter" many time if I want, so my terminal would look like this:
rosservice call /operatorshift/updateProgramSteps "category: ''
name: ''
steps:
- command: ''
args: ''
> - command: 'example'
> args: ''
>
Then I'm done editing this command, so I press the second shortcut, that retrieve what the first have deleted, and the "enter" key get its default behavior (execute the command)
rosservice call /operatorshift/updateProgramSteps "category: ''
name: ''
steps:
- command: ''
args: ''
> - command: 'example'
> args: ''
othersarg ''"
(not sure that '>' stay on screen after pressing the second shortcut)
I remember using it on Ubuntu 14.04, and on 16.04, with the default shell, without having to install a special package.
Just type "\", and when you press enter the ">" symbol you mentioned will appear
Sadly, I think the easiest solution is to use bash's edit-and-execute-command feature; from the manual:
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.
if you use bash in vi mode, you can invoke it by simply pressing v in normal mode.
This will open your command in your editor set up by $VISUAL or $EDITOR environmental variables.
Could it be heredoc ?
$ cat << EOF
> \$ Working dir "$PWD" `pwd`
> EOF
$ Working dir "/home/user" /home/user
If you want to re run a command with the same arguments you can do something like this:
vim long_filename
cat !$ #same as 'cat long_filename'
This saves having to type out the previous argument again when it is passed to cat.
However, how would I pass arguments that are not the same to the last run script/command?
long_annoying_script_name arg1 arg2
? arg3 arg4 #? signifies shortcut symbols such as '!$'
Of course I could just press the 'up' arrow and delete the arguments and type the new ones, but is there a shorter/faster way?
I DO NOT want to assign an alias.
!:0 should do the trick. From the zsh documentation:
Word Designators
A word designator indicates which word or words of a given command line
are to be included in a history reference. A `:' usually separates the
event specification from the word designator. It may be omitted only
if the word designator begins with a `^', `$', `*', `-' or `%'. Word
designators include:
0 The first input word (command).
n The nth argument.
^ The first argument. That is, 1.
$ The last argument.
% The word matched by (the most recent) ?str search.
x-y A range of words; x defaults to 0.
* All the arguments, or a null value if there are none.
x* Abbreviates `x-$'.
x- Like `x*' but omitting word $.
(It works with bash, too.) There’s also !-1 if you find that more convenient to type.
#TL;DR
Alt+0+.: inserts last command without the arguments
Tested on Ubuntu 18.04 with the default keybinding settings (i.e Emacs keybindings)
You can combine keyboard shortcuts
Let's consider the last command to be:
mv foo bar
up , Ctrl+w: last command without the last word = mv foo
Alt+0+.: first argument of last command = mv
Some useful shortcuts:
Alt+.: insert last argument from last command (repeat to go back in history)
Alt+number+.: insert #nth last argument from last command (repeat to go back in history)
Alt+- , number , Alt+., zsh: Alt+-+#+.: insert #nth first argument from last command (repeat to go back in history)
Cut commands (relative to cursor's position)
Ctrl+w: cuts last word
Alt+d: cuts next word
Ctrl+k: cuts everything after
Ctrl+u, zsh: Alt+w: cuts everything before
zsh: Ctrl+u: cuts the entire command (In bash you can combine Ctrl+u , Ctrl+k)
Ctrl+y: paste characters previously cut with any Cut command. In bash You can chain cut commands, and Ctrl+y will paste them all.
Ctrl+_: undo last edit (very useful when exceeding Ctrl+w)
Ctrl+left: move to last word
Ctrl+right: move to next word
home or Ctrl+a: move to start of command
end or Ctrl+e: move to end of command
To see all shortcuts available
bash: bind -lp
zsh: bindkey -L
Unfortunately there are some limitations
"words" only includes a-zA-Z characters, so any symbol character will stop word-shortcuts.
So if last argument was a url and you want to erase it with Ctrl+w it will be a pain.
E.g: curl -I --header "Connection: Keep-Alive" https://stackoverflow.com/questions/38176514/re-run-previous-command-with-different-arguments
To erase that url using Ctrl+w, you'd have to repeat it 12 times.
It would be great to have similar shortcuts that only stops at the space character
I'm keeping this up-to-date here: https://github.com/madacol/docs/blob/master/bash-zsh_TerminalShorcuts.md
Say I open two buffers side by side and enter the source code into buffer 1. I want to run the compiler (or any command line program) and see its output (stdout) in buffer 2.
How do I feed the current or specific buffer as stdin to this command line program? If this it not possible, I can save source code to the file and specfy it as parameter to compiler; but anyway I want to see output in buffer 2.
If you look at :h :b:
:[N]b[uffer][!] [+cmd] [N] :b :bu :buf :buffer E86
Edit buffer [N] from the buffer list. If [N] is not given,
the current buffer remains being edited. See :buffer-! for
[!]. This will also edit a buffer that is not in the buffer
list, without setting the 'buflisted' flag.
Also see +cmd.
And for +cmd:
+cmd [+cmd]
The [+cmd] argument can be used to position the cursor in the newly opened
file, or execute any other command:
+ Start at the last line.
+{num} Start at line {num}.
+/{pat} Start at first line containing {pat}.
+{command} Execute {command} after opening the new file.
{command} is any Ex command.
So:
:2b +r!date
Would open buffer 2, and read in the output of the date command.
You can use :r! command to execute shell command and read its output to current buffer.
:r !program opens a new line, inserts my program's output and then inserts a line after it.
I simply want to insert the output right where the cursor is without that additional mess.
I figured I can:
Run a before macro
mai^M^[`a
"Mark where I'm at, insert a line and go back
Run my command
:r !echo -ne "line1\nline2\nline3"
Run an after macro (cleanup the lines)
$mb:j!^M`a:j!^M`b
"Go to the end of inserted outpu
"Mark it b
"Join with the next line
"Go to the first mark
"Delete the inserted newline with :j!
"Go to the second mark
How can I combine this into a single command?
I'd like to be able to do:
:Readhere !echo -ne "line1\nline2\nline3"
where :Readhere would be my custom command.
This might do what you want. (You don't need the !)
command! -nargs=1 ReadHere exec 'normal! i' . system(<q-args>)
This creates a command called ReadHere that takes everything as a quoted argument and passes it directly to the system command. Then we use exec to insert everything in normal mode. (This might not be robust enough)
Example: Starting buffer is
one two three
Running :ReadHere echo -ne "line1\nline2\nline3" where the cursor is on the w produces
one tline1
line2
line3wo three