Bash reg-exp substitution - regex

Is there a way to run a regexp-string replace on the current line in the bash?
I find myself rather often in the situation, where I have typed a long commandline and then realize, that I would like to change a word somewhere in the line.
My current approach is to finish the line, press Ctrl+A (to get to the start of the line), insert a # (to comment out the line), press enter and then use the ^oldword^newword syntax (^oldword^newword executes the previous command after substituting oldword by newword).
But there has to be a better (faster) way to achieve this. (The mouse is not possible, since I am in an ssh-sessions most of the time).
Probably there is some emacs-like key-command for this, that I don't know about.
Edit: I have tried using vi-mode. Something strange happened. Although I am a loving vim-user, I had serious trouble using my beloved bash. All those finger-movements, that have been burned into my subconscious suddenly stopped working. I quickly returned to emacs-mode and considered, giving emacs a try as my favorite editor (although I guess, the same thing might happen again).

in ksh, in vi mode, if you hit 'v' while in command mode it will spawn a full vi session on the contents of your current command line. You can then edit using the full range of vi commands (global search and replace in your case). When :wq from vi, the edited command is executed. I'm sure something similar exists for bash. Since bash tends to extend its predecessors, there's probably something similar.

G'day,
What about using vi mode instead? Just enter set -o vi
Then you can go to the word you want to change and just do a cw or cW depending on what's in the word?
Oops, forgot to add you enter a ESC k to o to the previous line in the command history.
What do you normally use for an editor?
cheers,
Rob
Edit: What I forgot to say in my original reply was that you need to think of the vi command line in bash using the commands you enter when you are in "ex" mode in vi, i.e. after you've entered the colon.
Worst thing is that you need to move around through your command history using the ancient vi commands of h (to the left) and l (to the right). You can use w (or W) to bounce across words though.
Once you get used to it though, you have all sorts of commands available, e.g. entering ESC / my_command will look back through you r history, most recent first, to find the first occurrance of the command line containing the text my_command. Once it has found that, you can then use n to find the next occurrance, etc. And N to reverse the direction of the search.
I'd go have a read of the man page for bash to see what's available under vi mode. Once you get over the fact that up-arrow and down-arrow are replaced by ESC k, and then j, you'll see that vi mode offers more than emacs mode for command line editing in bash.
IMHO natchurly! (-:
Emacs? Eighty megs and constantly swapping!
cheers,
Rob

Unfortunately, no, there's not really a better way. If you're just tired of making the keystrokes, you can use macros to trim them down. Add the following to your ~/.inputrc:
"\C-x6": "\C-a#\C-m^"
"\C-x7": "\C-m\C-P\C-a\C-d\C-m"
Now, in a new bash instance (or after reloading .inputrc in your current shell by pressing C-x C-r), you can do the following:
Type a bogus command (e.g., ls abcxyz).
Press Ctrl-x, then 6. The macro inserts a # at the beginning of the line, executes the commented line, and types your first ^.
Type your correction (e.g., xyz^def).
Press Ctrl-x, then 7. The macro completes your substitution, then goes up to the previous (commented) line, removes the comment character, and executes it again.
It's not exactly elegant, but I think it's the best you're going to get with readline.

Related

how to do vi search and replace within a range in sublime text

I enabled vintage mode on sublime text.. but there are some important vim commands that are lacking.. so let's say I want to do a search and replace like so
:10,25s/searchedText/toReplaceText/gc
so I wanna search searchedText and replace it with toReplaceText from lines 10 to 25 and be prompted every time (ie yes/no)..
how do I do this with Sublime Text? everytime I hit : it gives me this funny menu.. any way around that?
If you so much would like to see vim in action, try the other way around; ie enable sublime stuff in vim.
Here are 2 links that might come in handy:
subvim and vim multiple cursors (Which is one amazing feature in sublime that lacks in native vim).
Hope that gets you creative ;)
Unfortunately vintage mode does not understand ranges. The best way I know how to do this is with incremental search:
highlight the first occurrence of searchedText on line 10
hit cmnd/ctrl D to have Sublime find the next occurence
If you you want the next occurrence ignored, hit cmnd/ctrl K
Once you have highlighted all the occurrences, you can replace them all at once, as Sublime has left cursors behind on every occurrence you opted in on.
VintageEx gives you a Vim-like command-line where you can at least perform substitutions. Well, that's how far I went when trying it. I don't know how extended the subset of Vim commands it implements is but I'd guess that it's not as large as the original and, like with Vintage, probably different and unsettling enough to keep a relatively experienced Vimmer out.
Anyway, I just tried it again and indeed you can more or less do the kind of substitution you are looking for, which instantly makes ST a lot more useful:
:3,5s/foo/bar/g
:.,5s/bar/foo/g
:,5/foo/bar/g
:,+5/bar/foo/g
Unfortunately, it doesn't support the /c flag.
a plugin named vintageous offers more features including search function. It's available in package control
although this question is answered.. i figured this would add some value
the full functionality of vi search/replace is possible with the ruby mine IDE, once you install the ideavim plugin. The idea is perfect for ruby on rails by the way.

alt+backspace to delete words in vim

How can I remap alt+backspace to delete words like native *NIX text manipulation? I checked out this thread: Using alt+backspace key in vim command line to delete by words
And the examples like: cmap <a-bs> <c-w> and :imap <A-BS> <C-W> don't do anything. And the accepted answer was actually to not even remap it, but to use ctrl+w. Since VIM's alt+backspace doesn't do anything I'd rather remap it to something I'm used to.
I'm using terminal based VIM (specifically in iTerm)
On macOS with iTerm2, I have the option keys mapped to +Esc (like many people), and I found that pressing Option+Backspace actually was interpreted by vim as an Escape press followed by a Backspace press, so the following binding worked perfectly for me; I recommend trying it even if your configuration is different than mine, just in case it works for you!
:imap <Esc><BS> <C-w>
The Alt/Meta key is problematic in Vim and most terminals, see this answer of mine for an overview of the situation (the situation is the same for Meta and Alt).
In short, Vim doesn't receive Alt at all: hitting Alt+Backspace is exactly the same as hitting Backspace.
Anyway, it will be better for you in the long term to learn and get accustomed to Vim's default key-mappings.
If you are on OSX, macvim uses the standard key bindings, so pressing Alt+Backspace will delete the entire word. Same goes for navigating between words with Alt+RightArrow and Alt+LeftArrow.

SAS Progam Editor on Unix

Is there a way to autoindent or a shortcut to insert a select number of spaces as a tab in the SAS Progam Editor on Unix?
I'm used to using the enhanced editor on PC and this is the only part of the switch that I can't find the answer to.
On the line numbers to the left of the code in the program editor, enter the >># command (replace # with a number) to indent '#' spaces to the right and <<# for shifting to the left. Enter these commands on the starting line and ending line. All rows inclusive between them will shift.
For a single line, ># or <#.
Without trying to start a flame-war... have you and your team considered NOT using the tab key in code? This way code always appears consistent regardless of editor/tab settings. Especially handy when you use a combination of vi/EG/SAS editor/notepad etc... I've worked at places that do this and it works great once you get everyone to agree to it.
When you open up existing code with tabs, just figure out how many spaces the tab is supposed to represent and do a search/replace.
It's still as fast to navigate quickly when you use, ctrl-left/ctrl-right in windows editors (and unix eds if setup that way), or 'w' and 'b' to jump to the next/previous word when using vi.
Cheers
Rob

Vim: Invert string (by words)

This is my string:
"this is my sentence"
I would like to have this output:
"sentence my is this"
I would like to select a few words on a line (in a buffer) and reverse it word by word.
Can anyone help me?
It's not totally clear what the context is here: you could be talking about text in a line in a buffer or about a string stored in a VimScript variable.
note: Different interpretations of the question led to various approaches and solutions.
There are some "old updates" that start about halfway through that have been rendered more or less obsolete by a plugin mentioned just above that section. I've left them in because they may provide useful info for some people.
full line replacement
So to store the text from the current line in the current buffer in a vimscript variable, you do
let words = getline('.')
And then to reverse their order, you just do
let words = join(reverse(split(words)))
If you want to replace the current line with the reversed words, you do
call setline('.', words)
You can do it in one somewhat inscrutable line with
call setline('.', join(reverse(split(getline('.')))))
or even define a command that does that with
command! ReverseLine call setline('.', join(reverse(split(getline('.')))))
partial-line (character-wise) selections
As explained down in the "old updates" section, running general commands on a character- or block-wise visual selection — the former being what the OP wants to do here — can be pretty complicated. Ex commands like :substitute will be run on entire lines even if only part of the line is selected using a character-wise visual select (as initiated with an unshifted v).
I realized after the OP commented below that reversing the words in a partial-line character-wise selection can be accomplished fairly easily with
:s/\%V.*\%V./\=join(reverse(split(submatch(0))))/
wherein
\%V within the RE matches some part of the visual selection. Apparently this does not extend after the last character in the selection: leaving out the final . will exclude the last selected character.
\= at the beginning of the replacement indicates that it is to be evaluated as a vimscript expression, with some differences.
submatch(0) returns the entire match. This works a bit like perl's $&, $1, etc., except that it is only available when evaluating the replacement. I think this means that it can only be used in a :substitute command or in a call to substitute()
So if you want to do a substitution on a single-line selection, this will work quite well. You can even pipe the selection through a system command using ...\=system(submatch(0)).
multiple-line character-wise selections
This seems to also work on a multiple-line character-wise selection, but you have to be careful to delete the range (the '<,'> that vim puts at the beginning of a command when coming from visual mode). You want to run the command on just the line where your visual selection starts. You'll also have to use \_.* instead of .* in order to match across newlines.
block-wise selections
For block-wise selections, I don't think there's a reasonably convenient way to manipulate them. I have written a plugin that can be used to make these sorts of edits less painful, by providing a way to run arbitrary Ex commands on any visual selection as though it were the entire buffer contents.
It is available at https://github.com/intuited/visdo. Currently there's no packaging, and it is not yet available on vim.org, but you can just git clone it and copy the contents (minus the README file) into your vimdir.
If you use vim-addon-manager, just clone visdo in your vim-addons directory and you'll subsequently be able to ActivateAddons visdo. I've put in a request to have it added to the VAM addons repository, so at some point you will be able to dispense with the cloning and just do ActivateAddons visdo.
The plugin adds a :VisDo command that is meant to be prefixed to another command (similarly to the way that :tab or :silent work). Running a command with VisDo prepended will cause that command to run on a buffer containing only the current contents of the visual selection. After the command completes, the buffer's contents are pasted into the original buffer's visual selection, and the temp buffer is deleted.
So to complete the OP's goal with VisDo, you would do (with the words to be reversed selected, and with the above-defined ReverseLine command available):
:'<,'>VisDo ReverseLine
old updates
...previous updates follow ... warning: verbose, somewhat obselete, and mostly unnecessary...
The OP's edit makes it more clear that the goal here is to be able to reverse the words contained in a visual selection, and specifically a character-wise visual selection.
This is decidedly not a simple task. The fact that vim does not make this sort of thing easy really confused me when I first started using it. I guess this is because its roots are still very much in the line-oriented editing functionality of ed and its predecessors and descendants. For example, the substitute command :'<,'>s/.../.../ will always work on entire lines even if you are in character-wise or block-wise (ctrlv) visual selection mode.
Vimscript does make it possible to find the column number of any 'mark', including the beginning of the visual selection ('<) and the end of the visual selection ('>). That is, as far as I can tell, the limit of its support. There is no direct way to get the contents of the visual selection, and there is no way to replace the visual selection with something else. Of course, you can do both of those things using normal-mode commands (y and p), but this clobbers registers and is kind of messy. But then you can save the initial registers and then restore them after the paste...
So basically you have to go to sort of extreme lengths to do with parts of lines what can easily done with entire lines. I suspect that the best way to do this is to write a command that copies the visual selection into a new buffer, runs some other command on it, and then replaces the original buffer's visual selection with the results, deleting the temp buffer. This approach should theoretically work for both character-wise and block-wise selections, as well as for the already-supported linewise selections. However, I haven't done that yet.
This 40-line code chunk declares a command ReverseCharwiseVisualWords which can be called from visual mode. It will only work if the character-wise visual selection is entirely on a single line. It works by getting the entire line containing the visual selection (using getline()) running a parameterized transformation function (ReverseWords) on the selected part of it, and pasting the whole partly-transformed line back. In retrospect, I think it's probably worth going the y/p route for anything more featureful.
" Return 1-based column numbers for the start and end of the visual selection.
function! GetVisualCols()
return [getpos("'<")[2], getpos("'>")[2]]
endfunction
" Convert a 0-based string index to an RE atom using 1-based column index
" :help /\%c
function! ColAtom(index)
return '\%' . string(a:index + 1) . 'c'
endfunction
" Replace the substring of a:str from a:start to a:end (inclusive)
" with a:repl
function! StrReplace(str, start, end, repl)
let regexp = ColAtom(a:start) . '.*' . ColAtom(a:end + 1)
return substitute(a:str, regexp, a:repl, '')
endfunction
" Replace the character-wise visual selection
" with the result of running a:Transform on it.
" Only works if the visual selection is on a single line.
function! TransformCharwiseVisual(Transform)
let [startCol, endCol] = GetVisualCols()
" Column numbers are 1-based; string indexes are 0-based
let [startIndex, endIndex] = [startCol - 1, endCol - 1]
let line = getline("'<")
let visualSelection = line[startIndex : endIndex]
let transformed = a:Transform(visualSelection)
let transformed_line = StrReplace(line, startIndex, endIndex, transformed)
call setline("'<", transformed_line)
endfunction
function! ReverseWords(words)
return join(reverse(split(a:words)))
endfunction
" Use -range to allow range to be passed
" as by default for commands initiated from visual mode,
" then ignore it.
command! -range ReverseCharwiseVisualWords
\ call TransformCharwiseVisual(function('ReverseWords'))
update 2
It turns out that doing things with y and p is a lot simpler, so I thought I'd post that too. Caveat: I didn't test this all too thoroughly, so there may be edge cases.
This function replaces TransformCharwiseVisual (and some of its dependencies) in the previous code block. It should theoretically work for block-wise selections too — it's up to the passed Transform function to do appropriate things with line delimiters.
function! TransformYankPasteVisual(Transform)
let original_unnamed = [getreg('"'), getregtype('"')]
try
" Reactivate and yank the current visual selection.
normal gvy
let #" = a:Transform(#")
normal gvp
finally
call call(function('setreg'), ['"'] + original_unnamed)
endtry
endfunction
So then you can just add a second command declaration
command! -range ReverseVisualWords
\ call TransformYankPasteVisual(function('ReverseWords'))
tangentially related gory detail
Note that the utility of a higher-level function like the ones used here is somewhat limited by the fact that there is no (easy or established) way to declare an inline function or block of code in vimscript. This wouldn't be such a limitation if the language weren't meant to be used interactively. You could write a function which substitutes its string argument into a dictionary function declaration and returns the function. However, dictionary functions cannot be called using the normal invocation syntax and have to be passed to call call(dictfunct, args, {}).
note: A more recent update, given above, obsoletes the above code. See the various sections preceding old updates for a cleaner way to do this.
Maybe:
:s/\v(.*) (.*) (.*) (.*)/\4 \3 \2 \1/
Of course you probably need to be more specific in the first part to find that particular sentence. Generally you can refer to match groups as \number with \0 being the whole match.
Here's a way to do by calling out to Ruby. After selecting the line you want to reverse, you can do this in command mode to replace it:
!ruby -e 'puts ARGF.read.strip.split(/\b/).reverse.join'
I found the solution myself thank to your answers and a lot of trying :)
This works:
function! Test()
exe 'normal ' . 'gv"ay'
let r = join(reverse(split(getreg('a'))))
let #a = r
exe 'normal ' . 'gv"ap'
endfunction
Didn't thought that I was enable to write such a function :)

Clearing terminal in Linux with C++ code

Okay, I have been researching on how to do this, but say I am running a program that has a whole bit of output on the terminal, how would I clear the screen from within my program so that I can keep my program running?
I know I can just type clear in terminal and it clears it fine, but like I said, for this program it would be more beneficial for me.
I found something that works, however, I'm not sure what it is or what it is doing.
cout << "\033[2J\033[1;1H";
That works but I have no clue what it is, if you could explain it, than I would much appreciate it.
These are ANSI escape codes. The first one (\033[2J) clears the entire screen (J) from top to bottom (2). The second code (\033[1;1H) positions the cursor at row 1, column 1.
All ANSI escapes begin with the sequence ESC[, have zero or more parameters delimited by ;, and end with a command letter (J and H in your case). \033 is the C-style octal sequence for the escape character.
See here for the full roadshow.
Instead of depending on specific escape sequences that may break in unexpected situations (though accepting that trade-off is fine, if it's what you want), you can just do the same thing you'd do at your shell:
std::system("clear");
Though generally system() is to be avoided, for a user-interactive program neither the extra shell parsing nor process overhead is significant. There's no problem with shell escaping either, in this case.
You could always fork/exec to call clear if you did want to avoid system(). If you're already using [n]curses or another terminal library, use that.
For portability you should get the string from termcap's cl (clear) capability (Clear screen and cursor home). (Or use std::system("clear") as told by Roger Pate).
man 3 termcap (in ncurses)
man 5 termcap
set | grep TERMCAP
you can write in a terminal "clear > data" and read in data the escapes sequance
0x1B[H0x1B[2J0x1B[3J
so
std::cout << "\033[H\033[2J\033[3J" ;