SED - insert a blank line after every input line that consists of capital letters and spaces - linux

I have a text file and I need a command using sed to insert a blank line after every line that that consists of capital letters and spaces only.

This might work for you (GNU sed):
sed '/^[[:blank:][:upper:]][[:blank:][:upper:]]*$/G' file
This appends the hold space (by default it contains a newline) to lines containing at least one or more whitespace or uppercase characters.

Given:
$ cat file
LINE LINE LINE
Line Line Line
Line 1
LINE 2
END!
====
You can use s/// to add a \n to the line:
With POSIX sed, use a literal new line in the sed script:
$ sed 's/^\([[:upper:][:blank:]]*\)$/\1\
/' file
LINE LINE LINE
Line Line Line
Line 1
LINE 2
END!
====
With GNU sed, you can use the representation of \n:
$ sed 's/^\([[:upper:][:blank:]]*\)$/\1\n/' file
You can also use a\ to append in sed. I have tried to get sed append to work but cannot reliably with POSIX, BSD and GNU sed since POSIX and BSD do not support \n
With GNU sed (note space after a\):
$ sed '/^[[:upper:][:blank:]]*$/a\ ' file
BSD:
$ sed '/^[[:upper:][:blank:]]*$/a\
\
' file
Those are not exactly equivalent since the GNU version has a space on the blank line.
The version of POSIX sed I have did not work with either of those...
Given the platform and version differences of sed, you might consider awk to do this since simple awk's are easier to make universal.
This works on every awk I have:
$ awk '1; /^[[:upper:][:blank:]]*$/{print ""}' file
With awk you can also make it so that blank lines are not doubled by making sure there is at least non blank like so:
$ awk '1; /^[[:upper:][:blank:]]+$/ && NF>1 {print ""}' file

Sure. Just insert lines with a:
sed '/^[[:blank:]A-Z]*$/a\'
The a command inserts the string after it after every matching line (end the string with a backslash). So the above command just inserts an empty line after all lines that contains solely of capital letters and spaces. That's exactly what you want.

Related

How to add text with sed at the end-of-line minus 1 position

I want to add the text [*,test,*] just before the last character of a line starting with resourceFilters: in the input file (that string can be preceded by any number of spaces).
An example of this line is the following
resourceFilters: '[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][Binding,*,*][ReplicaSet,*,*]'
which would be changed into this:
resourceFilters: '[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][Binding,*,*][ReplicaSet,*,*][*,test,*]'
sed "/^ *resourceFilters: '/s/'$/[*,test,*]'/" your_file
I've double quoted the Sed command so that I can use single quotes in it;
/^resourceFilters: '/ makes the following substitution command only act on lines starting with resourceFilters: ';
s/'$/[*,test,*]'/ is the substitution command which matches ' at end of line ($), and substitutes [*, test,*]' to it, effectively inserting [*,test,*] before the '.
This might work for you (GNU sed):
sed -E 's/^(\s*resourceFilters:.*)(.)$/\1[*,test,*]\2/' file
Match on a line containing resourceFilters: and insert [*,test,*] before the last character of the line.

strip all from line starting after whitespace

I have a file with this content:
lines
lines
rootdev=UUID=967d8dc3-f595-4a6e-929e-cc89as5a1a2s / ext4 defaults,
lines
I am searching for one line command which should strip everything in the line rootdev after whitespace, so the final content should be like:
lines
lines
rootdev=UUID=967d8dc3-f595-4a6e-929e-cc89as5a1a2s
lines
Any idea how to do it with one line command? (so I do not need to open nano with this file and do it manually)
I tried with sed but it just replaces the word rootdev
sed -i 's/rootdev//g' file.txt
Your attempt with sed can't work because it would just remove rootdev string with an empty string. What you need is a tool that matches a pattern and does an action on that whole line for which I think awk is more recommended than sed.
Using awk to match the line to strip off the spaces using gsub() should be sufficient,
awk '/^rootdev/{ gsub(/[[:space:]].*/,"",$0) }1' file
If you are using GNU awk with version greater than 4.1.0, you could use its in-place edit option to make the changes dynamically
gawk -i inplace '/^rootdev/{ gsub(/[[:space:]].*/,"",$0) }1' file
for earlier versions, use a temporary file
awk '/^rootdev/{ gsub(/[[:space:]].*/,"",$0) }1' file > temp && mv temp file
or use sponge from moreutils. If its not available in your system do get it on RHEL using yum install moreutils or with apt-get in Debian.
awk '/^rootdev/{ gsub(/[[:space:]].*/,"",$0) }1' file | sponge file
First, search for a line beginning with rootdev=, and when you find it delete everything after the first whitespace until the end of line.
sed -i '/^rootdev=/ s/ .*$//' file
Using a capturing group to keep rootdev=... part in, and replacing the whole line with it is an option too.
sed -i 's/^\(rootdev=[^ ]*\).*$/\1/' file

Replace first six commas for each line in a text file

I want to replace the first six , for each line in a text file using sed or something similar in linux.
There are more than six , on each line, but only the first six should be replaced by |.
Sed doesn't really support the notion of "the first n occurrences", only "the n-th occurrence"; GNU sed has one for "replace all matches from the n-th on", which is not what you want in this case. To get the first six commas replaced, you have to call the s command six times:
sed 's/,/|/;s/,/|/;s/,/|/;s/,/|/;s/,/|/;s/,/|/' infile
If, however, you know that there are no | in the file and you have GNU sed, you can do this:
sed 's/,/|/g;s/|/,/7g' infile
This replaces all commas with pipes, then turns the pipes from the 7th on back to commas.
If you do have pipes beforehand, you can turn them into something that you know isn't in the string first:
sed 's/|/~~/g;s/,/|/g;s/|/,/7g;s/~~/|/g' infile
This makes all | into ~~ first, then all , into |, then the | from the 7th on back into ,, and finally the ~~ back into |.
Testing on this input file:
,,,,,,X,,,,,,
,,,|,,,|,,,|,,,|
the first and third command result in
||||||X,,,,,,
||||||||,,,|,,,|
The second one would fail on the second line because there are already pipe characters.
This might work for you (GNU sed):
sed 'y/,/\n/;s/\n/,/7g;y/\n/|/' file
Translate all ,'s to \n's, then replace from the seventh \n to the end of line by ,'s, then replace the remaining \n's by |'s.
Use the following pattern in sed: sed 's/old/new/<number>'
Where <number> is the number of times you want this pattern applied.
You can replace <number> with g to apply the pattern to all occurrences.
You can try this sed,
sed -r ':loop; s/^([^,]*),/\1|/g; /^([^|]*\|){6}/t; b loop' file
(OR)
sed ':loop; s/^\([^,]*\),/\1|/g; /^\([^|]*|\)\{6\}/t; b loop' file
Test:
$ cat file
a,b,c,d,e,f,g,h,i,j,k
$ sed -r ':loop; s/^([^,]*),/\1|/g; /^([^|]*\|){6}/t; b loop' file
a|b|c|d|e|f|g,h,i,j,k
Note: This will work only if you do not have any pipe(|) before that.

sed can't differentiate CR from LF if both exist in the same file

I have a file where CR (\r) and LF (\n) exists in the same file.
a1 a2 CRLF
b1 LF
b2 CRLF
c1 c2 CRLF
The file need to be fixed to:
a1 a2 CRLF
b1 b2 CRLF
c1 c2 CRLF
The logic is simple: remove LF that is not preceded by CR with empty string:
sed 's/[^\r]\n//g' input.txt > output.txt
However, this doesn't work!
I had to delete all the occurrences of LF, and replace all the remaining CR with CRLF :
cat input.txt | tr -d '\n' | sed 's/\r/\r\n/g' >output.txt
this bugs me. why isn't sed working??
#Etan Reisner is basically correct - sed handles text as newline-delimited lines, so you need to jump through some hoops to make it deal with newlines directly. Just because you can do this doesn't mean it's the cleanest way, but if you don't have other tools at your disposal, here's an example of how to do this:
sed -e 's/[^\r]$/&/' -e te -e b -e :e -e N -e 's/\n//'
What this command does is:
s/[^\r]$/&/ - replace a CR at the end of a line with ... itself.
te - test and branch: if the previous substitution succeeded, branch to the indicated label. (We needed it to succeed, which is why it substituted with itself)
b - unconditionally branch to the end of the script
:e - create a label for the earlier te command to jump to
N - append the next line into the pattern space. This results in a pattern space with an embedded newline.
s/\n// - delete the embedded newline.
sed doesn't see line endings in the line it is operating on.
This is the same reason that sed 's/\n//' doesn't give you a file with only one line.
The newlines are handled "internally".
This is the sort of task that dos2unix/unix2dos/etc. may handle for you more directly.
I'd use awk:
awk -v RS='\r\n' 'BEGIN { ORS = RS } { gsub(/\n/, ""); print }'
With the record separator RS set to \r\n, the file will be split into records separated by, well, \r\n, so removing newlines in those records removes all newlines that are not preceded by \r. Setting ORS (the output record separator) to RS makes it so that the output file still has CRLF line endings.
Note that multi-character RS is not strictly POSIX-conforming. The most common awks support it, though.
Or there's the Perl way:
perl -pe 's/(?<!\r)\n//'
This relies on a negative lookbehind; (?<!\r) matches an empty string that is not preceded by \r. Note that unlike sed, Perl without -l does not remove newlines from the input, so no special tricks are necessary to remove them.

Inserting string in file in nth line after pattern using sed

I want to insert word after nth line after pattern using sed.
I tied to modify this command but it inserts only in first line after pattern.
sed -i '/myPattern/a \ LineIWantToinser ' myFile
What command should I use to insert for example in third line after pattern?
Easiest way to do it with GNU sed is.. (maybe some direct solution exists!?)
sed -n '/pattern/=' file
to see line where pattern is (grep also can be used here with -n)
then if linenumber+ numoflines is for example 123
sed '123aSOME INSERTED TEXT AFTER THAT LINE' file
where little a is append command (after that line, if i is used will be pre pattern line)
ps. I'm eager to see if #neronlevelu (or other sed Lover) will find some better sed solution.
Edit: i've found it, it seems a for append or i for insert must? be on first position on line when using { with ; inside } like
sed '/pattern/{N;N;N;
a SOME TEXT FOR INSERTING
}' file
sed '/pattern/{N;N;N;i \
Line to add after 3 lines with patterne as starting counter
' YourFile
number of N to add line between pattern and inserted line.
there is no check for end of file or pattern in the 3 lines. (not specified in PO)
A version with bash and ed:
ed -s myFile <<<$'/myPattern/+3a\n LineIWantToinser \n.\nwq'
ed enables us to use the line addressing /myPattern/+3.

Resources