sed
is very peculiar about r
ead - it will only do it for the line which matched its pattern - and it will always do it last. sed
won't r
ead out a file for a matching pattern if the pattern ceases to match before it flushes the line. At least that's how I think it works - I'm pretty good with sed
but r
still baffles me sometimes.
Anyway, the trick is to let it flush the line with the pattern it wants - thereby ensuring the output for that line, but to delay that output at least by one line and then to edit it.
You can do this relatively easily w/ N;P;D
- which will work in concert to advance sed
's line counter at least one line ahead of lines printed. Consider the following two files:
###file1
some string 1
some string 2
some other string
some string 4
some string 5
###file2
some other file
Now my goal is to perform a substitution replacing the pattern on which r
ead depends, and to get r
ead to print its contents before my change is printed. Here's how I do it:
sed '$!N;s/other \(.*\)\(\n\)/\1 3\2/
/\n.*other/r file2
P;D' file1
OUTPUT
some string 1
some string 2
some other file
some string 3
some string 4
some string 5
I also did this with a different file2 which printed...
some string 1
some string 2
no trailing newline some string 3
some string 4
some string 5
I do have some fairly deep reservations about the portability of that behavior, but that was with a GNU sed
, for what it's worth.
Ok, so in the above commands, sed
is reading its input one line ahead of when it prints it. N
appends the next input line to pattern space, P
prints up to the first \n
ewline character in pattern space, and D
deletes up to the first \n
ewline character in pattern space before starting over with what remains. So every line we see printed is one line behind sed
's look at it - sed
gets a two-line window on the input.
The pattern which matches r
ead matches only for when a \n
ewline character occurs before it which it matches for the cycle when sed
first pulls it in with N
- it only matches the cycle in which we don't see it.
The replacement only occurs when the \n
ewline occurs after the pattern - this is the cycle on which it will be P
rinted, after all, but sed
flushes its line buffer and increments the line when we pull in the N
ext line, so the r
gets printed then and then the replacement occurs. Kind of tedious really, but then so am I.
And speaking of GNU sed
it does offer a rather interesting option for situations like these, in fact.
sed '/other/{x;s/.*/cat file2/e;G
s/\(.*\)\n\(.* \)other \(.*\)/\1 \2\3 3/
}' file
info sed
will tell you...
e [COMMAND]
This command allows one to pipe input from a shell command into
pattern space. Without parameters, the `e' command executes the
command that is found in pattern space and replaces the pattern
space with the output; a trailing newline is suppressed.
There I also do a little pattern space shuffling - I want a blank pattern space in which to run my command, and so I switch to unused hold space. But it is a little more simple to understand because you don't have to consider line flush timings. It is, essentially, what has been suggested by other means already, with perhaps a little benefit in that any of sed
's special characters will not generate an error if they exist in the target read file.
Oh by the way, the above prints:
some string 1
some string 2
some other file some string 3
some string 4
some string 5
<TEXT>
supposed to be? Where is the replacement pattern? Is it in File1? If so, is it a multiline pattern? Could you add an example? Are you just looking forfoo=$(cat file1); sed "s/$foo/replacement/"
? – terdon Oct 26 '14 at 19:56needle.txt
andsubject.txt
? Show example. Anyway I think this is XY problem. – jimmij Oct 26 '14 at 20:39sed 's/^\(<?php\).*\(?><?php\)$/\1replace\2/' subject.txt
? – Costas Oct 26 '14 at 20:40sed 's/^<?php.*\(<?php\)$/\1/'
did the trick for me. can you answer if that's possible to read the search part from a file without worring about if it need escaping? – sepehr Oct 26 '14 at 20:53sed "s/$(cat needle.txt)/replace/"
Or you asking for script file to dial assed -f script.file subject.file
? – Costas Oct 26 '14 at 21:03[
and it's opposite]
which clarify bybash
asrange
. So we need to escape them. Just a tricksed "s/$(cat needle.txt | sed 's/[][]/\\&/g')/replace/"
– Costas Oct 26 '14 at 21:43