What's the simplest way to do a find and replace for a given input string, say abc
, and replace with another string, say XYZ
in file /tmp/file.txt
?
I am writting an app and using IronPython to execute commands through SSH — but I don't know Unix that well and don't know what to look for.
I have heard that Bash, apart from being a command line interface, can be a very powerful scripting language. So, if this is true, I assume you can perform actions like these.
Can I do it with bash, and what's the simplest (one line) script to achieve my goal?
The easiest way is to use sed (or perl):
sed -i -e 's/abc/XYZ/g' /tmp/file.txt
Which will invoke sed to do an in-place edit due to the -i
option. This can be called from bash.
If you really really want to use just bash, then the following can work:
while IFS='' read -r a; do
echo "${a//abc/XYZ}"
done < /tmp/file.txt > /tmp/file.txt.t
mv /tmp/file.txt{.t,}
This loops over each line, doing a substitution, and writing to a temporary file (don't want to clobber the input). The move at the end just moves temporary to the original name. (For robustness and security, the temporary file name should not be static or predictable, but let's not go there.)
For Mac users:
sed -i '' 's/abc/XYZ/g' /tmp/file.txt
(See the comment below why)
File manipulation isn't normally done by Bash, but by programs invoked by Bash, e.g.:
perl -pi -e 's/abc/XYZ/g' /tmp/file.txt
The -i
flag tells it to do an in-place replacement.
See man perlrun
for more details, including how to take a backup of the original file.
perl -pi -e 's/chdir (?:\\/[\\w\\.\\-]+)+/chdir blah/g' text
, but I keep getting an error with Having no space between pattern and following word is deprecated at -e line 1. Unmatched ( in regex; marked by <-- HERE in m/(chdir)( )( <-- HERE ?:\\/ at -e line 1.
I was surprised when I stumbled over this...
There is a replace
command which ships with the "mysql-server"
package, so if you have installed it try it out:
# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt
# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"
See man replace
for more on this.
replace
is a useful independent tool and the MySQL folks should release it separately and depend on it b) replace
requires some bit of MySQL o_O Either way, installing mysql-server to get replace would be the wrong thing to do :)
mysql-server
package installed. As pointed by @rayro, replace
is part of it.
This is an old post but for anyone wanting to use variables as @centurian said the single quotes mean nothing will be expanded.
A simple way to get variables in is to do string concatenation since this is done by juxtaposition in bash the following should work:
sed -i -e "s/$var1/$var2/g" /tmp/file.txt
sed "s/\"$li\"/- [x]\"\${li:5}\"/" $dat
ang get sed unterminated `s' command
Bash, like other shells, is just a tool for coordinating other commands. Typically you would try to use standard UNIX commands, but you can of course use Bash to invoke anything, including your own compiled programs, other shell scripts, Python and Perl scripts etc.
In this case, there are a couple of ways to do it.
If you want to read a file, and write it to another file, doing search/replace as you go, use sed:
sed 's/abc/XYZ/g' <infile >outfile
If you want to edit the file in place (as if opening the file in an editor, editing it, then saving it) supply instructions to the line editor 'ex'
echo "%s/abc/XYZ/g
w
q
" | ex file
Example is like vi
without the fullscreen mode. You can give it the same commands you would at vi
's :
prompt.
for
loop.
for f in report*.txt; do echo "%s/abc/XYZ/g \n w \n q \n" | ex file; done
is clean and simple. Why put functionality into ex
that the shell already has?
I found this thread among others and I agree it contains the most complete answers so I'm adding mine too:
sed and ed are so useful...by hand. Look at this code from @Johnny: sed -i -e 's/abc/XYZ/g' /tmp/file.txt
When my restriction is to use it in a shell script, no variable can be used inside in place of "abc" or "XYZ". The BashFAQ seems to agree with what I understand at least. So, I can't use: x='abc'
y='XYZ'
sed -i -e 's/$x/$y/g' /tmp/file.txt
#or,
sed -i -e "s/$x/$y/g" /tmp/file.txt
but, what can we do? As, @Johnny said use a while read... but, unfortunately that's not the end of the story. The following worked well with me: #edit user's virtual domain
result=
#if nullglob is set then, unset it temporarily
is_nullglob=$( shopt -s | egrep -i '*nullglob' )
if [[ is_nullglob ]]; then
shopt -u nullglob
fi
while IFS= read -r line; do
line="${line//'
The most suitable solution I can think of with the given assumptions of the problem.
sed -e "s/$x/$y/"
, and it will work. Not the double quotes. It can get seriously confusing if the strings in the variables themselves contain characters with special meaning. For example if x="/" or x="\". When you hit these issues, it probably means you should stop trying to use the shell for this job.
You can use sed
:
sed -i 's/abc/XYZ/gi' /tmp/file.txt
You can use find
and sed
if you don't know your filename:
find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;
Find and replace in all Python files:
find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;
-i
isn't "ignore case", it's -i[SUFFIX], --in-place[=SUFFIX]
(edit files in place (makes backup if SUFFIX supplied))
Be careful if you replace URLs with "/" character.
An example of how to do it:
sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"
Extracted from: http://www.sysadmit.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html
If the file you are working on is not so big, and temporarily storing it in a variable is no problem, then you can use Bash string substitution on the whole file at once - there's no need to go over it line by line:
file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt
The whole file contents will be treated as one long string, including linebreaks.
XYZ can be a variable eg $replacement
, and one advantage of not using sed here is that you need not be concerned that the search or replace string might contain the sed pattern delimiter character (usually, but not necessarily, /). A disadvantage is not being able to use regular expressions or any of sed's more sophisticated operations.
You may also use the ed
command to do in-file search and replace:
# delete all lines matching foobar
ed -s test.txt <<< $'g/foobar/d\nw'
See more in "Editing files via scripts with ed
".
sed -i <pattern> <filename>
). Very nice!
To edit text in the file non-interactively, you need in-place text editor such as vim.
Here is simple example how to use it from the command line:
vim -esnc '%s/foo/bar/g|:wq' file.txt
This is equivalent to @slim answer of ex editor which is basically the same thing.
Here are few ex
practical examples.
Replacing text foo
with bar
in the file:
ex -s +%s/foo/bar/ge -cwq file.txt
Removing trailing whitespaces for multiple files:
ex +'bufdo!%s/\s\+$//e' -cxa *.txt
Troubleshooting (when terminal is stuck):
Add -V1 param to show verbose messages.
Force quit by: -cwq!.
See also:
How to edit files non-interactively (e.g. in pipeline)? at Vi SE
-V1
, to force quit, use wq!
.
Try the following shell command:
find ./ -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
sed
, use sed -i''
instead.
You can use python within the bash script too. I didn't have much success with some of the top answers here, and found this to work without the need for loops:
#!/bin/bash
python
filetosearch = '/home/ubuntu/ip_table.txt'
texttoreplace = 'tcp443'
texttoinsert = 'udp1194'
s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, 'w')
f.write(s)
f.close()
quit()
Simplest way to replace multiple text in a file using sed command
Command -
sed -i 's#a/b/c#D/E#g;s#/x/y/z#D:/X#g;' filename
In the above command s#a/b/c#D/E#g where I am replacing a/b/c with D/E and then after the ; we again doing the same thing
You can use rpl command. For example you want to change domain name in whole php project.
rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/
This is not clear bash of cause, but it's a very quick and usefull. :)
For MAC users in case you don't read the comments :)
As mentioned by @Austin, if you get the Invalid command code
error
For the in-place replacements BSD sed
requires a file extension after the -i
flag to save to a backup file with given extension.
sed -i '.bak' 's/find/replace' /file.txt
You can use ''
empty string if you want to skip backup.
sed -i '' 's/find/replace' /file.txt
All merit to @Austin
In case of doing changes in multiple files together we can do in a single line as:-
user_name='whoami'
for file in file1.txt file2.txt file3.txt; do sed -i -e 's/default_user/${user_name}/g' $file; done
Added if in case could be useful.
Success story sharing
sed
:s/..../..../ - Substitute
and/g - Global
invalid command code C
error... For in-place replacements, BSDsed
requires a file extension after the-i
flag because it saves a backup file with the given extension. For example:sed -i '.bak' 's/find/replace/' /file.txt
You can skip the backup by using an empty string like so:sed -i '' 's/find/replace/' /file.txt
s/abc/XYZ/gi