using sed to move dynamic string from one file and appending to second file - string

i'm trying to move a dynamic string from a file and append it to the second file with sed.
what I have tried so far:
sed -i -e '/To300/{w /home/test/test1.txt' -e 'd}' /home/test/test2.txt
where XXXXTo300 is the string I want to move. Its moving the string to the second file, but when the next string is moved, its overwriting the existing strings in the second file.
thanks

In general, this won't work, as sed overwrites the file each time you use the command. However, if you use GNU sed, you can work around this limitation by writing to stdout and redirecting:
sed -i -e '/To300/{w /dev/stdout' -e ';d }' oldfile >> newfile

Related

Sed how to find and replace a value using a bash variable [duplicate]

I have a configuration file (gpsd.default) containing data with the following format:
# If you must specify a non-NMEA driver, uncomment and modify the next line
GPSD_SOCKET="/var/run/gpsd.sock"
GPSD_OPTIONS=""
GPS_DEVICES=""
I am making a change on the file with sed:
sed -i 's/^GPS_DEVICES="".*/GPS_DEVICES="dev/ttyUSB1"/' /etc/default/gpsd.default
or
sed -i '4s/^.*/GPS_DEVICES="dev/ttyUSB1"/' /etc/default/gpsd.default
The above sed command returns error:
sed: bad option in substitution expression
Because the new line contains "/" in its expression.
How to update my sed command to make it work?
This is because you are using a regex containing /, which is the same character sed uses as delimiter.
Just change the sed delimiter to another one, for example ~:
sed -i 's~^GPS_DEVICES="".*~GPS_DEVICES="dev/ttyUSB1"~' /etc/default/gpsd.default
By the way, since you are changing files in /etc, you may want to use -i.bak, so that the original file gets backed up. It is a good practice to prevent loss of important information.
You should update your sed command to this.
sed -i 's/^GPS_DEVICES=\"\".*/GPS_DEVICES=\"dev\/ttyUSB1\"/' /etc/default/gpsd.default

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/'

Sed error : bad option in substitution expression

I have a configuration file (gpsd.default) containing data with the following format:
# If you must specify a non-NMEA driver, uncomment and modify the next line
GPSD_SOCKET="/var/run/gpsd.sock"
GPSD_OPTIONS=""
GPS_DEVICES=""
I am making a change on the file with sed:
sed -i 's/^GPS_DEVICES="".*/GPS_DEVICES="dev/ttyUSB1"/' /etc/default/gpsd.default
or
sed -i '4s/^.*/GPS_DEVICES="dev/ttyUSB1"/' /etc/default/gpsd.default
The above sed command returns error:
sed: bad option in substitution expression
Because the new line contains "/" in its expression.
How to update my sed command to make it work?
This is because you are using a regex containing /, which is the same character sed uses as delimiter.
Just change the sed delimiter to another one, for example ~:
sed -i 's~^GPS_DEVICES="".*~GPS_DEVICES="dev/ttyUSB1"~' /etc/default/gpsd.default
By the way, since you are changing files in /etc, you may want to use -i.bak, so that the original file gets backed up. It is a good practice to prevent loss of important information.
You should update your sed command to this.
sed -i 's/^GPS_DEVICES=\"\".*/GPS_DEVICES=\"dev\/ttyUSB1\"/' /etc/default/gpsd.default

How can I remove the last character of a file in unix?

Say I have some arbitrary multi-line text file:
sometext
moretext
lastline
How can I remove only the last character (the e, not the newline or null) of the file without making the text file invalid?
A simpler approach (outputs to stdout, doesn't update the input file):
sed '$ s/.$//' somefile
$ is a Sed address that matches the last input line only, thus causing the following function call (s/.$//) to be executed on the last line only.
s/.$// replaces the last character on the (in this case last) line with an empty string; i.e., effectively removes the last char. (before the newline) on the line.
. matches any character on the line, and following it with $ anchors the match to the end of the line; note how the use of $ in this regular expression is conceptually related, but technically distinct from the previous use of $ as a Sed address.
Example with stdin input (assumes Bash, Ksh, or Zsh):
$ sed '$ s/.$//' <<< $'line one\nline two'
line one
line tw
To update the input file too (do not use if the input file is a symlink):
sed -i '$ s/.$//' somefile
Note:
On macOS, you'd have to use -i '' instead of just -i; for an overview of the pitfalls associated with -i, see the bottom half of this answer.
If you need to process very large input files and/or performance / disk usage are a concern and you're using GNU utilities (Linux), see ImHere's helpful answer.
truncate
truncate -s-1 file
Removes one (-1) character from the end of the same file. Exactly as a >> will append to the same file.
The problem with this approach is that it doesn't retain a trailing newline if it existed.
The solution is:
if [ -n "$(tail -c1 file)" ] # if the file has not a trailing new line.
then
truncate -s-1 file # remove one char as the question request.
else
truncate -s-2 file # remove the last two characters
echo "" >> file # add the trailing new line back
fi
This works because tail takes the last byte (not char).
It takes almost no time even with big files.
Why not sed
The problem with a sed solution like sed '$ s/.$//' file is that it reads the whole file first (taking a long time with large files), then you need a temporary file (of the same size as the original):
sed '$ s/.$//' file > tempfile
rm file; mv tempfile file
And then move the tempfile to replace the file.
Here's another using ex, which I find not as cryptic as the sed solution:
printf '%s\n' '$' 's/.$//' wq | ex somefile
The $ goes to the last line, the s deletes the last character, and wq is the well known (to vi users) write+quit.
After a whole bunch of playing around with different strategies (and avoiding sed -i or perl), the best way i found to do this was with:
sed '$! { P; D; }; s/.$//' somefile
If the goal is to remove the last character in the last line, this awk should do:
awk '{a[NR]=$0} END {for (i=1;i<NR;i++) print a[i];sub(/.$/,"",a[NR]);print a[NR]}' file
sometext
moretext
lastlin
It store all data into an array, then print it out and change last line.
Just a remark: sed will temporarily remove the file.
So if you are tailing the file, you'll get a "No such file or directory" warning until you reissue the tail command.
EDITED ANSWER
I created a script and put your text inside on my Desktop. this test file is saved as "old_file.txt"
sometext
moretext
lastline
Afterwards I wrote a small script to take the old file and eliminate the last character in the last line
#!/bin/bash
no_of_new_line_characters=`wc '/root/Desktop/old_file.txt'|cut -d ' ' -f2`
let "no_of_lines=no_of_new_line_characters+1"
sed -n 1,"$no_of_new_line_characters"p '/root/Desktop/old_file.txt' > '/root/Desktop/my_new_file'
sed -n "$no_of_lines","$no_of_lines"p '/root/Desktop/old_file.txt'|sed 's/.$//g' >> '/root/Desktop/my_new_file'
opening the new_file I created, showed the output as follows:
sometext
moretext
lastlin
I apologize for my previous answer (wasn't reading carefully)
sed 's/.$//' filename | tee newFilename
This should do your job.
A couple perl solutions, for comparison/reference:
(echo 1a; echo 2b) | perl -e '$_=join("",<>); s/.$//; print'
(echo 1a; echo 2b) | perl -e 'while(<>){ if(eof) {s/.$//}; print }'
I find the first read-whole-file-into-memory approach can be generally quite useful (less so for this particular problem). You can now do regex's which span multiple lines, for example to combine every 3 lines of a certain format into 1 summary line.
For this problem, truncate would be faster and the sed version is shorter to type. Note that truncate requires a file to operate on, not a stream. Normally I find sed to lack the power of perl and I much prefer the extended-regex / perl-regex syntax. But this problem has a nice sed solution.

Execute a cat command within a sed command in Linux

I have a file.txt that has some content. I want to search for a string in file1.txt, if that string is matched I want to replace that string with the content of the file.txt. How can I achieve this?
I have tried using sed:
sed -e 's/%d/cat file.txt/g' file1.txt
This is searching for the matching string in the file1.txt and replacing that with the string cat file.txt, but I want contents of file.txt instead.
How about saving the content of the file in the variable before inserting it into sed string?
$content=`cat file.txt`; sed "s/%d/${content}/g file1.txt"
Given original.txt with content:
this is some text that needs replacement
and replacement.txt with content:
no changes
I'm not sure what your replacement criteria is, but lets say I want to replace all occurrences of the word replacement in the original file, you may replace the content of the original text with the content of the other file using:
> sed -e 's/replacement/'"`cat replacement.txt`"'/g' original.txt
this is some text that needs no changes
You can read a file with sed using the r command. However, that is a line-based operation, which may not be what you're after.
sed '/%d/r file1.txt'
The read occurs at the end of the 'per-line' cycle.

Resources