How do I delete the first line of the hold space in sed?
I've tried
x;
s/.*\n//;
x;
But .*\n matches up to the last newline, deleting all the lines except for the last one.
this should remove the 1st line from "hold space"
x;s/[^\n]*\n//
Example:
kent$ sed -n 'H;${x;p}' <(seq 3)
1
2
3
remove the first empty line:
kent$ sed -n 'H;${x;s/[^\n]*\n//;p}' <(seq 3)
1
2
3
Simple put any random string with h i.e 1h;1d, by default it's empty.
Related
I am using following command to append string after AMP, but now I want to add after to AMP which is after SET2 or line number 9, can we modify this command to append the string only after SET2 or line number 9? And if I want to add to only to SET1 AMPs or before line number 9 , could someone help me with the command, thanks.
$ sed -i '/AMP/a Target4' test.txt
$ cat test.txt
#SET1
AMP
Target 1
Target 2
AMP
Target 3
Target 4
Target 5
#Set2
AMP
Target 11
Target 12
Note there is no line between above text.
Would you please try the following:
sed -i '
/^#Set2/,${ ;# if the line starts with "#Set2", execute the {block} until the last line $
/AMP/a Target4 ;# append the string after "AMP"
} ;# end of the block
' test.txt
If you want to append the string before the #Set2 line, please try:
sed -i '
1,/^#Set2/ { ;# excecute the {block} while the line number >= 1 until the line matches the pattern /^#Set2/
/AMP/a Target4
}
' test.txt
The expression address1,address2 is a flip-flop operator. Once the
address1 (line number, regular expression, or other condition) meets,
the operator keeps on returning true until the address2 meets.
Then the following command or block is executed from address1 until
address2.
If you want to add to after AMP which is after #Set2 or line number 9,
I think it is better to process up to the 8th line and after the 9th line separately.
For example, the command is below:
sed '
1,8{
/^#Set2/,${
/AMP/a Target4
}
}
9,${
/AMP/a Target4
}' test.txt
My sed script is this:
# script.sed
1,3H
1,3g
3D
When I run it, I get the following:
$ seq 5 | sed -f script.sed
1
1
2
4
5
However, this seems wrong to me. On line 3, once the D command is executed, the pattern space has
1
2
3
When the cycle is restarted, H should set the hold space to:
<empty_line>
1
2
3
1
2
3
Then, g should set the pattern space to the same content. D will then remove the first (empty) line. Every time the cycle is restarted, the hold space will effectively double. Hence, this should lead to an infinite loop.
What am I missing?
Below, I show how I interpret the expected execution, showing as an ordered pair the result of the command, with the pattern space first and the hold space following:
1: H(1,\n1) g(\n1,\n1) > \n1\n
2: H(2,\n1\n2) g(\n1\n2,\n1\n2) > \n1\n2\n
3: H(3,\n1\n2\n3) g(\n1\n2\n3,\n1\n2\n3) D(,\n1\n2\n3) >
4: > 4\n
5: > 5\n
If I take the output of this interpretation and concatenate it into an echo command with the -e option, I get:
$ echo -e '\n1\n\n1\n2\n4\n5\n'
1
1
2
4
5
I have a text file of the form:
a = 1
#b = [2,3]
c = 4
d = [5,6]
e = [7,8]
I want to replace the pattern inside the brackets (and the brackets) with a number, but ignore matches in the comments, preferably using sed.
For files with exactly one matching line, I've used
sed -i "/^#/!s/\[.*\]/9/" myfile
How can this be modified to replace only the first match if there are more?
This is the correct, because changing just the first occurence.
awk '!end && /^[^#]+ = \[/ {$3="9"; end=1}1' myfile
if there is not end flag and line is not beggining from # and match to = [, then change the third column and set the flag to prevent changing in next occurences.
a = 1
#b = [2,3]
c = 4
d = 9
e = [7,8] <--- this is not changed as you want
This one-liner should do the job:
sed '/^\s*#/!{s/\[[^]]*\]/9/}' file
add the -i option if you like to do the change in place.
I would like to include tab as delimited new row to a file inp.txt.
This is the input produced by R:
inp <- 'AX-1 1 125
AX-2 2 456
AX-3 3 3445'
inp <- read.table(text=inp, header=F)
write.table(inp, "inp.txt", col.names=F, row.names=F, quote=F, sep="\t")
That´s what I am trying to do:
sed -i '1i The name\tThe pos\tThe pos2\' inp.txt
However, those three col names: 1- The name, 2- The pos, 3- The pos2 are not separated by tab in the output file. It just contain the \t string. Someone can help me here with the syntax?
Put the tab in a variable:
tab=$(echo "\t")
or
tab=$'\t'
Then you can use it in your sed script:
sed -i "1i The name${tab}The pos${tab}The pos2" inp.txt
I'm trying to replace two consecutive lines based on a pattern match, and would want this to repeat for the entire file. Here is the input file:
c aaaaa bbb
+ 0.1
c xxxx
c yyyy
+ 0.2
* c gggg
m eeeee hhhhh
+ 0.3
The command I tried is:
sed '/^c/{N;s/+/*+/}'
I expected to see a * prepended to each line beginning, but only those lines immediatlely following a c line:
c aaaaa bbb
*+ 0.1
c xxxx
c yyyy
*+ 0.2
* c gggg
m eeeee hhhhh
+ 0.3
what I actually get:
c aaaaa bbb
*+ 0.1
c xxxx
c yyyy
+ 0.2
* c gggg
m eeeee hhhhh
+ 0.3
Here, i see only the first occurrence of + (with previous line beginning with c) is getting replaced with *+. The second occurrence of + in the file is not getting replaced.
What am I doing wrong? How do I get the result I want: replacement happens in multiple consecutive lines in the file?
The problem you run into is that when a line that starts with c comes right after another line that comes with c, the N command in your code consumes it, and it isn't available for checking when you process the line that comes next.
Instead of reading ahead to see if the next line should be changed, I'd remember the last line and look back to see if the current line should be changed:
sed 'x; G; /^c/ s/+/*+/; s/.*\n//' file
This works as follows:
x # Swap pattern space and hold buffer. Because we do this here,
# the previous line will be in the hold buffer for every line
# (except the first, then it is empty)
G # append hold buffer to pattern space. Now the pattern space
# contains the previous line followed by the current line.
/^c/ s/+/*+/ # If the pattern space begins with a c (i.e., if the previous
# line began with a c), replace + with *+
s/.*\n// # Remove the first line (the previous one) from the pattern
# space
# Then drop off the end. The changed current line is printed.
sed -e 'H;$!d' -e 'x' -e ':cycle' -e 's/\(\nc[[:alnum:][:blank:][:punct:]]*\n\)+/\1*+/g;t cycle' -e 's/.//' YourFile
Posix version changing the whoe in max 2 internal cycle
load the file in memory (-e 'H;$!d' -e 'x')
Add the * in front of line starting with a + after a line starting with a c ( s/\(\nc[[:alnum:][:blank:][:punct:]]*\n\)+/\1*+/g)
do the same if occur in previous line ( :cycle and t cycle)
use a trick to insure starting with new line( H append current line to buffer also for first line so an extra new line as heading) (for first line with a c) and remove this at the end ('s/.//)