One line bash Script to Edit File (not create a new one) - linux

I'm a newbie at bash script and I'm trying to write a bash script to edit a configuration file. i want to remove " foo" from the file.
Using the code
echo
sed -e "s/ foo//" ./test > ./test2
will create a new file with the content i want. But if i try to edit the same file using this
echo
sed -e "s/ foo//" ./test > ./test
the file will just become empty. Is this not the way? how can i simply edit a file? thanks.

This is what the -i switch is for: edit-in-place:
sed -i -e "s/ foo//" ./test
The -i switch is documented in man sed:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)
For GNU sed (linux), no back-up is created when the suffix is omitted. For other versions of sed, it might be mandatory to supply a backup suffix.

Empty file
Shell opens the file test for writing -> clearing all its previous contents.
How to edit same file
Solution 1:- inline change
sed -i.bk "s/ foo//" ./test
Solution 2:- use intermediate file (manual version of previous cmd)
sed -e "s/ foo//" ./test > test.bk && mv test.bk test

Sed is a [s]tream [ed]itor, not a text editor. Using the '-i' parameter is not POSIX, plus it adds the overhead of creating a temporary file before replacing the original file.
If you want to edit your files truly in place, you should use ed/ex instead.
ex -sc '%s/ foo//g|xit' ./test
See the manual pages sed(1p), ed(1p) and ex(1p).

Related

Comments in sed command file

Can I put comments (or something functionally equivalent) into a sed command file?
subs.sed
s/this/that/g
# comment
s/it/they/g
$ sed -i -f subs.sed <(echo this it)
that they
Yes, comments can be added to a sed file using #.
From the manual page of sed:
Command Synopsis
...
#comment
The comment extends until the next newline (or the end of a -e script fragment).

How to use sed to replace variable value declared in a text file

I would like to edit the /etc/environment file to change the MY_VARIABLE from VALUE_01 to VALUE_02.
Here is the context of the /etc/environment file:
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
JAVA_HOME="/usr/java/jdk8/jdk1.8.0_92-1"
MY_VARIABLE=VALUE_01
Ideally I would like to use sed command to edit it, for example (please note it is not working command):
sed -e 'MY_VARIABLE=VALUE_02' -i /etc/environment
How can I achieve it?
sed -- 's/MY_VARIABLE=.*/MY_VARIABLE=VALUE_02/' /etc/environment
Once you check it works, add the -i option:
sed -i -- 's/MY_VARIABLE=.*/MY_VARIABLE=VALUE_02/' /etc/environment
You will probably need root access.
Instead of trying to use sed -i and hoping your version of sed implements that option and working out if it takes a mandatory argument or not (I have a feeling you're not using GNU sed like the linux tag suggests you should be), just use ed to edit files in scripts.
ed -s /etc/environment <<EOF
/^MY_VARIABLE=/c
MY_VARIABLE=VALUE_02
.
w
EOF
changes the first line starting with MY_VARIABLE= to the given new text, and writes the file back to disk.

How to replace a entire line from a file which has a content /u02/app/oracle-1/product/12.2.0/db_1:N to /u01/app/oracle/product/12.2.0/db_1:Y

Can we do it using sed and if so how?
How to replace a entire line from a file which has a content /u02/app/oracle-1/product/12.2.0/db_1:N to /u01/app/oracle/product/12.2.0/db_1:Y using Sed
It is very easy with sed command. Use below sed command which will do it for you.
sed 's|'/u02/app/oracle-1/product/12.2.0/db_1:N'|'/u01/app/oracle/product/12.2.0/db_1:Y'|g' your_original_file > newfile
mv newfile your_original_file
In above example, first sed command will replace /u02/app/oracle-1/product/12.2.0/db_1:N with /u01/app/oracle/product/12.2.0/db_1:Y and modified text will be redirect to newfile. In the new file you can review the changes whether correct or not.
With mv command you can rename newfile to your_original_file. So above example is safe. But you can do so with a single command like below, but you should be careful here, because if anything wrong you will be in trouble :-)
sed -i.bak 's|'/u02/app/oracle-1/product/12.2.0/db_1:N'|'/u01/app/oracle/product/12.2.0/db_1:Y'|g' yourfile
After lot of trials got it done.
sudo sed -i.bak '/^G:/u01/app/oracle/product/12.2.0/db_1:/ s/N/Y/'

How to substitute two lines in same text files [duplicate]

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.
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.
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
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.
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//'<servername>'/$server}"
line="${line//'<serveralias>'/$alias}"
line="${line//'<user>'/$user}"
line="${line//'<group>'/$group}"
result="$result""$line"'\n'
done < $tmp
echo -e $result > $tmp
#if nullglob was set then, re-enable it
if [[ is_nullglob ]]; then
shopt -s nullglob
fi
#move user's virtual domain to Apache 2 domain directory
......
As one can see if nullglob is set then, it behaves strangely when there is a string containing a * as in:
<VirtualHost *:80>
ServerName www.example.com
which becomes
<VirtualHost ServerName www.example.com
there is no ending angle bracket and Apache2 can't even load.
This kind of parsing should be slower than one-hit search and replace but, as you already saw, there are four variables for four different search patterns working out of one parse cycle.
The most suitable solution I can think of with the given assumptions of the problem.
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' {} \;
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".
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
Try the following shell command:
find ./ -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
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
Open file using vim editor. In command mode
:%s/abc/xyz/g
This is the simplest
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.

How to substitute without creating intermediate file in sed?

I was doing some hands-on with the Unix sed command. I was trying out the substitution and append command, in a file. But the difficulty is, I have to create an intermediate file, and then do mv to rename it to the original file.
Is there any way to do it at one shot in the same file?
[root#dhcppc0 practice]# sed '1i\
> Today is Sunday
> ' file1 > file1
[root#dhcppc0 practice]# cat file1
[root#dhcppc0 practice]#
The file is deleted!
[root#dhcppc0 practice]# sed 's/director/painter/' file1 > file1
[root#dhcppc0 practice]# cat file1
The file is deleted!
Try this -
sed -i '' 's/originaltext/replacementtext/g' filename | cat filename
-i '' is meant for providing a backup file. If you are confident your replacement won't cause an issue you can put '' to pass no backup file
/g is for replacing globally. If you have more than one originaltext in one line then with /g option will replace all else it will only replace the first.
GNU sed knows an option -i which does in-place edit of the given files.
When doing an operation file1 > file1 what actually happens is, that the file is opened and truncated by the shell before the program (which gets it's name as argument) comes around reading anything from it.
Update:
sed's man page states the following on the -i option (thanks Delan for mentioning it):
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)
sed -i.bak 's/director/painter/' file1
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)

Resources