Re run previous command with different arguments - linux

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

Related

why is vim's delete command so slow

I have a file that contains about 5000 lines and I want to delete all lines that have 'some_string' so I first search for /some_string then I execute :g//d. This takes over 5 minutes to delete ~90% of the lines. What gives?
In comparison, if I run sed -i '/some_string/d' some_file it takes 46ms.
Add an underscore to your command.
I experienced a similar problem and it turned out to be each line being copied to my system clipboard. By adding a _, you tell vim to use the blackhole register.
:g//d_
The help gives the following syntax for :d
:[range]d[elete] [x] Delete [range] lines (default: current line) [into register x].

Understanding how a Sed script breaks down into individual commands

I'm new to sed, can you tell me what the following does? I can't find a complete regex in the command from below.
sed -e ':a;N;$!ba;s/>[[:space:]]*\n/>\\\n/g' nlTest1.txt > nlTest2.txt
Are we having 3 commands together?
:a;N;$!ba;s
>[[:space:]]*\n
>\\\n/g
Or I'm not intrepreting the command correctly.
The partitioning of the commands is:
:a;N;$!ba, which is a common idiom for reading the entire input file into the pattern space (buffer to operate on) at once, in a loop; it is composed of 3 ;-separated commands:
label :a (defines a script location that can be jumped to)
function N (reads the next line and appends it to the pattern space)
$! ba, which branches (b) to label a, if the input line is not (!) the last ($) one.
s/>[[:space:]]*\n/>\\\n/g is a regular s function call in the form s/<regex>/<substitution-string>/; here, all occurrences of a > followed by any run of whitespace followed by a newline are replaced with just >\ and a newline.

Terminal command line quick navigation

I would like to move between the command line arguments in a fast way. For example, if I have the following command line:
> do_something_with /very_long_path/to_a_very_long_directory/ more_args
^ ^
I would like to skip the whole path (jump between the ^ symbols). I'm already familiar with word mode (Alt+B and Alt+F) but in some scenarios it's not enough to navigate quickly between the arguments.
In bash, you can set the cursor to the previous given character using the following features:
character-search and character-search-backward features.
ctrl+], (resp. alt+ctrl+]) + searched_character
In your example, you can search backward for a space.
> do_something_with /very/long/path/\ with_spaces\ directory/ more_args
^ ^
Unfortunately, this will not work so well with paths like:
> do_something_with /very_\ long_path/to_a_\ very_long_directory/ more_args
As a sidenote, you can use ctrl+a and ctrl+e to go at the beginning / end of a line.
There are (quote from manual)
shell-forward-word ()
Move forward to the end of the next word. Words are delimited by non-quoted shell metacharacters.
and
shell-backward-word ()
Move back to the start of the current or previous word. Words are delimited by non-quoted shell metacharacters.
I have bound them to Ctrl+Alt+F and Ctrl+Alt+B by adding this to my .inputrc:
"\e\C-f": shell-forward-word
"\e\C-b": shell-backward-word
For vi/vim users ctrl+] + char can be used to quickly navigate to the first occurance of a given char. Which is equivalent to f + char in vi/vim.

vi keep only first 10 characters of a column

how do i do this in vi?
awk -F"," awk '{print substr($1,1,10)}'
I only want to keep the first 10 characters of my date column (example 2014-01-01) and not include the timestamp.
I tried to do it in awk but i got this error:
sed: RE error: illegal byte sequence
I believe it is a bash_profile setting error.
This is what i have in my bash_profile:
#export LANG=en_US.UTF-8
#export LOCALE=UTF-8
export LC_CTYPE=C
export LANG=C
in vim, do:
:%norm! 11|D
this will affect all lines in your buffer.
If you like, :s could do this job too.
:%s/.\{,10}\zs.*//
:%s/: apply the substitution to all the lines
.\{,10}: match anything up to 10 times (greedy)
\zs: indicates the beginning of the match
.*: match the rest of the line
/: end of the first part of :s
/: end of the second part of s (since there's nothing between the two /, replace with nothing, ie delete)
For editing blocks of text there is a -- VISUAL BLOCK -- mode accessible via CTRL-V (on Windows ussually CTRL-Q). Then you can press d to delete your selection.
Or with a simple substitute command
:%s/\%>10c.*//
\%>10c - matches after tenth column
. - matches any single character but not an end-of-line
* - matches 0 or more of the preceding atom, as many as possible
Or you can use range
:1,3s/\%>10c.*//
This would substitute for the first three lines.

What is the shorthand for the first argument of the previous comment in bash? last is '$!'

What is the special character which indicate first ?
if we do
$ vi .bashrc
$ source !$
this !$ will replaced by .bashrc
because ! means previous line(am I correct?), $ means last word (for sure)
then what is first?
I want to insert some string in every line in vi editor using
:%s/find-key-word/replaced-keyword/g
in here, if I put
:%s/$/example/g
in vi editor, it will append in all lines with example.
I want to insert all in front of all string every line.
I know I can use visual block (ctrl+v) and select all front lines and insert (shift+i) insert some word and escape(esc) will do the same... but I want to do in one shot..
please let me know how to do..
Thanks in advance
There are two questions, so you are getting two kinds of answers :)
The bash command history has only a passing similarity to the vi regular expression syntax.
^ is the beginning of line in vi. $ is the end of line in vi.
!!:0 is one way of accessing the first word of the previous command in bash
!$ is one way of accessing the last word of the previous command in bash
To indicate beginning of line, the symbol used is:
^
See an example:
$ cat a
hello!
this is me
testing some
stuff
$ sed 's/^/XXX/' a
XXXhello!
XXXthis is me
XXXtesting some
XXXstuff
The character you are looking for is ^.
For example, :%s/^/example/g will prepend all lines with the string example.
In bash, !^ refers to the first argument of the previous command, and !$ the last argument.

Resources