Related
I can use
:5,12s/foo/bar/g
to search for foo and replace it by bar between lines 5 and 12. How can I do that only in line 5 and 12 (and not in the lines in between)?
Vim has special regular expression atoms that match in certain lines, columns, etc.; you can use them (possibly in addition to the range) to limit the matches:
:5,12s/\(\%5l\|\%12l\)foo/bar/g
See :help /\%l
You can do the substitution on line 5 and repeat it with minimal effort on line 12:
:5s/foo/bar
:12&
As pointed out by Ingo, :& forgets your flags. Since you are using /g, the correct command would be :&&:
:5s/foo/bar/g
:12&&
See :help :& and friends.
You could always add a c to the end. This will ask for confirmation for each and every match.
:5,12s/foo/bar/gc
Interesting question. Seems like there's only range selection and no multiple line selection:
http://vim.wikia.com/wiki/Ranges
However, if you have something special on line 5 and 12, you could use the :g operator. If your file looks like this (numbers only for reference):
1 line one
2 line one
3 line one
4 line one
5 enil one
6 line one
7 line one
8 line one
9 line one
10 line one
11 line one
12 enil one
And you want to replace one by eno on the lines where there's enil instead of line:
:g/enil/s/one/eno/
You could use ed - a line oriented text editor with similar commands to vi and vim. It probably predates vi and vim.
In a script (using a here document which processes input till the EndCommand marker) it would look like:
ed file <<EndCommands
5
s/foo/bar/g
7
s/foo/bar/g
wq
EndCommands
Obviously, the ed commands can be used on the command line also.
Let's say I'm in a buffer like this, on line 4, I want to run line 1 to 2 and have the output in the same buffer on line 4 (where cursor is):
echo "Testing"
echo "more testing"
# and here I want the output from running lines 1 to 2
...I know I can do 1,2w !sh to run lines 1 and 2 and have the output shown in whatever that temporary buffer is. But, how do I get into my actual buffer for later editing?
(And the same thing to work with visual mode selected text, not just with line ranges given by numbers.)
You were using :w !... (:help :w_c), but you probably want :! (:help :!):
gg - go to top
Vj - select the two lines
y - yank into a buffer
4gg - go to 4th line
V - select it
p - paste over it
gv - reselect the pasted range
:!sh<CR> - execute in shell and replace
or, trusting ex commands more,
:4d
:1,2y
:3pu
:4,5!sh
NB: !sh is in most cases equivalent to !, as ! will call your default shell.
Yey! Found it. In case anyone else needs this exact same hack on a virgin/foreign vim (plugin-less or someone else's server/config):
:1,2r !sh %
(yeah, output goes after commands, or technically the commands are replaced with their echo but whatever, not at cursor position, but good enough for me to replicate my Sublime + SublimeCommand workflow in vim :) )
Is there a way to grep on the output of print command in gdb? In my case, I am debugging a core dump using gdb and the object I am debugging contains hell lots of elements. I am finding it difficult to look for a matching attribute i.e:
(gdb) print *this | grep <attribute>
Thanks.
You can use pipe command
>>> pipe maintenance info sections | grep .text
[15] 0x5555555551c0->0x5555555554d5 at 0x000011c0: .text ...
>>> pipe maintenance info sections | grep .text | wc
1 10 100
(gdb) print *this | grep
The "standard" way to achieve this is to use Meta-X gdb in emacs.
An alternative:
(gdb) set logging on
(gdb) print *this
(gdb) set logging off
(gdb) shell grep attribute gdb.txt
The patch mentioned by cnicutar sure looks attractive compared to the above. I am guessing the reason it (or its equivalent) was never submitted is that most GDB maintainers use emacs, and so don't have this problem in the first place.
The simplest way is to exploit gdb python. One-liner:
gdb λ py ["attribute" in line and print(line) for line in gdb.execute("p *this", to_string=True).splitlines()]
Assuming you have enabled history of commands, you can type this just once, and later then press Ctrl+R b.exec to pull it out of history. Next simply change attribute and *this per your requirements.
You can also make this as simple as this:
gdb λ grep_cmd "p *this" attribute
For that just add the following to your .gdbinit file:
py
class GrepCmd (gdb.Command):
"""Execute command, but only show lines matching the pattern
Usage: grep_cmd <cmd> <pattern> """
def __init__ (_):
super ().__init__ ("grep_cmd", gdb.COMMAND_STATUS)
def invoke (_, args_raw, __):
args = gdb.string_to_argv(args_raw)
if len(args) != 2:
print("Wrong parameters number. Usage: grep_cmd <cmd> <pattern>")
else:
for line in gdb.execute(args[0], to_string=True).splitlines():
if args[1] in line:
print(line)
GrepCmd() # required to get it registered
end
I know this is an old post but since I found it looking to do the same thing I thought I would add to Hi-Angel's answer to say you can highlight the search term, in the python output, in a red colour by replacing the print line with the one below:
print(line.replace(args[1], "\033[91m"+args[1]+"\033[0m"))
This just uses ascii escape commands for the colour, so should work on Linux and Windows terminal, and you can easily change the colour.
Sorry, don't have enough rep to add this as a comment.
I have a file that has around million lines. I need to go to line number 320123 to check the data. How do I do that?
With n being the line number:
ng: Jump to line number n. Default is the start of the file.
nG: Jump to line number n. Default is the end of the file.
So to go to line number 320123, you would type 320123g.
Copy-pasted straight from Wikipedia.
To open at a specific line straight from the command line, use:
less +320123 filename
If you want to see the line numbers too:
less +320123 -N filename
You can also choose to display a specific line of the file at a specific line of the terminal, for when you need a few lines of context. For example, this will open the file with line 320123 on the 10th line of the terminal:
less +320123 -j 10 filename
You can use sed for this too -
sed -n '320123'p filename
This will print line number 320123.
If you want a range then you can do -
sed -n '320123,320150'p filename
If you want from a particular line to the very end then -
sed -n '320123,$'p filename
From within less (in Linux):
g and the line number to go forward
G and the line number to go backwards
Used alone, g and G will take you to the first and last line in a file respectively; used with a number they are both equivalent.
An example; you want to go to line 320123 of a file,
press 'g' and after the colon type in the number 320123
Additionally you can type '-N' inside less to activate / deactivate the line numbers. You can as a matter of fact pass any command line switches from inside the program, such as -j or -N.
NOTE: You can provide the line number in the command line to start less (less +number -N) which will be much faster than doing it from inside the program:
less +12345 -N /var/log/hugelogfile
This will open a file displaying the line numbers and starting at line 12345
Source: man 1 less and built-in help in less (less 418)
For editing this is possible in nano via +n from command line, e.g.,
nano +16 file.txt
To open file.txt to line 16.
I know that Esc + . gives you the last argument of the last command.
But I'm interested in first argument of the last command.
Is there a key binding to do so?
On the same lines, is there a generic way of getting the nth argument from the last command?
I know that in a bash script, you can use $0, $1 etc., but these don't work on the commandline.
Also, what about iterating through the 0th argument of previous commands, like we can do with the last argument by continuously pressing Esc + .?
!$ gets the last element of the previous command line argument.
Just as M-. (meta-dot or esc-dot or alt-dot) is the readline function yank-last-arg, M-C-y (meta-control-y or esc-ctrl-y or ctrl-alt-y) is the readline function yank-nth-arg. Without specifying n, it yanks the first argument of the previous command.
To specify an argument, press Escape and a number or hold Alt and press a number. You can do Alt--to begin specifying a negative number then release Alt and press the digit (this will count from the end of the list of arguments.
Example:
Enter the following command
$ echo a b c d e f g
a b c d e f g
Now at the next prompt, type echo (with a following space), then
Press Alt-Ctrl-y and you'll now see:
$ echo a
without pressing Enter yet, do the following
Press Alt-3 Alt-Ctrl-y
Press Alt-- 2 Alt-Ctrl-y
Now you will see:
$ echo ace
By the way, you could have put the echo on the line by selecting argument 0:
Press Alt-0 Alt-Ctrl-y
Edit:
To answer the question you added to your original:
You can press Alt-0 then repeatedly press Alt-. to step through the previous commands (arg 0). Similarly Alt-- then repeating Alt-. would allow you to step through the previous next-to-last arguments.
If there is no appropriate argument on a particular line in history, the bell will be rung.
If there is a particular combination you use frequently, you can define a macro so one keystroke will perform it. This example will recall the second argument from previous commands by pressing Alt-Shift-Y. You could choose any available keystroke you prefer instead of this one. You can press it repeatedly to step through previous ones.
To try it out, enter the macro at a Bash prompt:
bind '"\eY": "\e2\e."'
To make it persistent, add this line to your ~/.inputrc file:
"\eY": "\e2\e."
Unfortunately, this doesn't seem to work for arg 0 or negative argument numbers.
To use the first argument, you can use !^ or !:1
Example:
$ echo a b c d e
a b c d e
$ echo !^
echo a
a
$ echo a b c d e
a b c d e
$ echo !:1
echo a
a
Since your question is about using any other arguments, here are some useful ones:
!^ first argument
!$ last argument
!* all arguments
!:2 second argument
!:2-3 second to third arguments
!:2-$ second to last arguments
!:2* second to last arguments
!:2- second to next to last arguments
!:0 the command
!! repeat the previous line
The first four forms are more often used. The form !:2- is somewhat counter-intuitive, as it doesn't include the last argument.
I liked #larsmans answer so much I had to learn more. Adding this
answer to help others find the man page section and know what to
google for:
$ man -P 'less -p ^HISTORY\ EXPANSION' bash
<...>
Word Designators
Word designators are used to select desired words from the event.
A : separates the event specification from the word designator.
It may be omitted if the word designator begins with a ^, $, *, -,
or %. Words are numbered from the beginning of the line, with the
first word being denoted by 0 (zero). Words are inserted into the
current line separated by single spaces.
0 (zero)
The zeroth word. For the shell, this is the command word.
n The nth word.
^ The first argument. That is, word 1.
$ The last argument.
% The word matched by the most recent ‘?string?’ search.
x-y A range of words; ‘-y’ abbreviates ‘0-y’.
* All of the words but the zeroth.
This is a synonym for ‘1-$’.
It is not an error to use * if there is just one word in
the event; the empty string is returned in that case.
x* Abbreviates x-$.
x- Abbreviates x-$ like x*, but omits the last word.
If a word designator is supplied without an event
specification, the previous command is used as the event.
Tested on Ubuntu 18.04
To insert previous arguments:
Alt+.: insert last argument from last command.
Alt+#+.: insert #nth last argument from last command.
Alt+- , # , Alt+., zsh: Alt+-+#+.: insert #nth first argument from last command.
In Linux you can repeat commands to go back in history
Example:
Last command is:
mv foo bar
Alt+0+.: insert first argument of last command = mv
Alt+2+.: insert last 2nd argument of last command = foo
up , Ctrl+w: last command without the last word = mv foo
General shortcuts
Ctrl+w: removes last word from cursor
Alt+d: removes next word from cursor
Ctrl+k: cuts everything after cursor
Ctrl+u, zsh: Alt+w: cuts everything before cursor
zsh: Ctrl+u: cuts the entire command (In bash you can combine Ctrl+u , Ctrl+k)
Ctrl+y: paste characters previously cut with Ctrl+u and Ctrl+k
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 line
end or Ctrl+e: move to end of line
To iterate through the arguments in a previous command
only works in zsh
run or add this to your ~/.zshrc
autoload -Uz copy-earlier-word
zle -N copy-earlier-word
bindkey "^[:" copy-earlier-word
Now use Alt+. to go as back as you want, then use Alt+: to iterate through the arguments
Assuming last command is
echo 1 2 3 4 5
Alt+.: 5
Alt+.+:: 4
Alt+.+:+:: 3
Alt+.+:+:+:: 2
Alt+.+:+:+:+:: 1
Alt+.+:+:+:+:+:: echo
source: https://stackoverflow.com/a/34861762/3163120
To see all shortcuts available
bash: bind -lp
zsh: bindkey -L
I'm keeping this up-to-date here: https://github.com/madacol/knowledge/blob/master/bash-zsh_TerminalShorcuts.md
!^ may be the command for the first argument. i'm not sure if there is a way to get the nth.
You can also get arguments from any command in your history!
$ echo a b c d e f g
a b c d e f g
$ echo build/libs/jenkins-utils-all-0.1.jar
build/libs/jenkins-utils-all-0.1.jar
$ history | tail -5
601 echo build/libs/jenkins-utils-all-0.1.jar
602 history | tail -10
603 echo a b c d e f g
604 echo build/libs/jenkins-utils-all-0.1.jar
605 history | tail -5
$ echo !-3:4
echo d
d
$ echo !604:1
echo build/libs/jenkins-utils-all-0.1.jar
build/libs/jenkins-utils-all-0.1.jar
!^ will get you the first param, !$ will get you the last param, !:n will get you the nth element.
Basically it has a use in yanking previous (command's) arguments.
For instance, if the following command is issued:
echo Hello, world how are you today?
then, Hello, will be the first argument, and today? the sixth, that is the last one; meaning it can be referenced by typing:
Alt+6 followed by Ctrl-Alt-6
Ctrl is traditionally denoted as a hat character ^ prepended to keys names, and Alt as M- that is Meta prefix.
So the above shortcut can be redefined as ^My to yank.
Also, there is hats substitution shortcut in the command line:
echo Hello, world!
^Hello^Bye
Bye, world!
to substitute the previous command's first matched string, meaning:
Hello, world! Hello, people!
^Hello^Bye
would result in:
Bye, world! Hello, people!
leaving the second match (hello) unchanged.
Note: Do not leave space between hats, or the operation won't work.
The above is just a shortcut for:
!:s/Hello/Bye
event-level(*) substitution for the first found (matched) string in the previous command, while prefixing the first part with the g switch will apply to the whole line globally:
echo Hello, world! Hello, people!
!:gs/Hello/Bye
Bye, world! Bye, people!
as usually being done in other related commands such as sed, vi, and in regex (regular expression) - a standart way to search (match string).
No, you can't do !:sg/Hello/Bye or !:s/Hello/Bye/g here, that's the syntax!
! is for events; event might be understood as command output or operation done in the commands history.
That's what I understood by using it myself and trying things on my own from what I read from various sources including manual pages, blogs, and forums.
Hope it will shed some light into mysterious ways of bash, the Bourne-Again shell (a play on sh shell, which itself is called Bourne shell after its inventor's last name), what is default shell in many distributions including servers (server OS's).
The method described at the end of the accepted answer also works with the zeroth argument for me. I have these lines in my ~/.inputrc:
"\en": "\e0\e."
"\em": "\e1\e."
"\e,": "\e2\e."
\e2\e. has the advantage over \e2\e\C-y that it cycles through previous commands if it is pressed repeatedly instead of inserting the second argument of the previous command multiple times.
To insert the whole previous command, you can type !!\e^. \e^ is history-expand-line.
If you are on a mac you will tend to get extended characters with ctrl+letter. I have my right-of-space-bar-option key defined as meta in my terminal (iTerm2) set up. This means I use the key to navigate by word and pull parameters from previous commands.
For pasting 1th argument, press and hold down Alt key, and while it is down, hit the '1' key followed by the '.' key.
For pasting n-th argument, replace the '1' key above with the corresponding number key.
If this does not work, your terminal emulator may be catching the Alt key before it gets to shell. Some terminals (xfce4-terminal) allow turning off the "Alt-" shortcuts in the configuration file.
Credit to Jonas Eberle, I've fished this out from his comment to another answer here.