How can I replace ALL instances of a string in the previous command in Bash?

Bash

Bash Problem Overview


If I have just entered the following command in Bash:

echo foo

I can change foo to bar by typing:

^foo^bar

Which results in the following command being executed:

echo bar

Now if I enter:

echo foo foo

Is there a way to change both instances of foo to bar just by using the caret (^) operator?

Additionally, are there man pages for shell operators like ^? man ^ results in "No manual entry for ^".

Bash Solutions


Solution 1 - Bash

That particular feature is called quick substitution; its documentation can be found in the Event Designators section of the Bash Manual. You can't do what you want with quick substitution; you'll have to resort to something slightly more verbose:

!!:gs/foo/bar/

Solution 2 - Bash

Nor sure how to do it with caret substitution, but here's how you do it with history:

!!:gs/foo/bar/

Let me break that down:

> !! - reruns the last command. You can also use !-2 to run two commands ago, !echo to run the last command that starts with echo > > :gs says to do a global (all instances) search/replace. If you wanted to just do replace the first instance, you would use ':s' > > Finally, /foo/bar/ says to replace foo with bar

Solution 3 - Bash

Try:

^foo^bar^:&

As you know ^foo^bar^ performs just one substitution, and the :& modifier repeats it.

Solution 4 - Bash

Caret substitution and other similar shortcuts are found in the Event Designators subsection of the HISTORY EXPANSION section of the bash(1) man page.

Solution 5 - Bash

If you're looking for something less difficult to memorize that accomplishes the same thing as the above !!:gs/foo/bar/, you could always create a function in your .bash_profile start-up script. I chose replace().

replace() {
    eval $(echo $(fc -ln -1) | eval "sed 's/${1}/${2}/g'") #compact form
}

OR, Less convolutedly

replace() {
    string=$(fc -ln -1) #gets last command string
    repcmmd="sed 's/${1}/${2}/g'" #build replacement sed command from fn input
    eval $(echo $string | eval $repcmmd) #evaluates the replacement command
}

Then the replace all can be made with

echo foo foo
replace foo bar

Solution 6 - Bash

^word^  ........... erase word
^word^^ ........... delete everything until the end of the line

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmattjamesView Question on Stackoverflow
Solution 1 - BashAdam RosenfieldView Answer on Stackoverflow
Solution 2 - BashR Samuel KlatchkoView Answer on Stackoverflow
Solution 3 - BashFlatEartherView Answer on Stackoverflow
Solution 4 - BashIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 5 - BashMLPView Answer on Stackoverflow
Solution 6 - BashSergioAraujoView Answer on Stackoverflow