?? sed: how to use "1 s/" with -i to replace pattern only once?
I think I shouldn't need to be asking this, but I've been frigging around with this and reading sed tutorials for some time now, and I just can't get this to work.
In a text file, I have a bunch of identical lines, like this: blah.. #STUB #STUB #STUB #STUB #STUB more blah.. .. and I want to use sed -i to replace only the FIRST of those #STUB things, with a replacement. It works in the console, without -i like so: Code:
bash-3.1# echo "#RULESTUB Code:
sed -i "1 s/^#STUB$/replacement/" $file What am I missing? NOTE: if it matters, the sed operation is double quoted because in the real-world situation, 'replacement' is a $variable. Sasha |
^ and $ are the beginning and end of line anchors. Your search pattern will only match a line that contains exactly "#STUB\n"
|
That's *exactly* what the line(s) contains..
|
in that case, double check your line endings and shell quoting (in case something is eating your end-of-line $), since I just pasted your example into a file here and it works alright.
|
Oh!! You may have just got it -- update in a moment...
Nope.. I had thought maybe the $ was being interpreted literally, but it isn't.. FWIW, the replacement operation works fine without the "1 " but it replaces ALL the instances of #STUB, instead of quitting after one replacement. So the regex isn't the problem; in fact, I have an earlier line(s) in the script which use a similar regex, and it works fine (but that earlier line is SUPPOSED to replace ALL instances). |
do you mean the first instance in a line, or the first instance in the file?
|
First instance in the file. I think I may have identified the problem though.. It may be PEBKAC :rolleyes:
Back in a moment. |
ah. make sure your quotes are escaped. I haven't got any idea about replace once per file.
|
I'm relieved to NOT have to admit it was PEBKAC :)
But it isn't a quote-escape issue; I use double quotes often for stuff like this, when either the PATTERN or REPLACEMENT is a variable. But still, in this case, I'm stumped. It won't work... Still trying though! Thanks for the feedback so far. Sasha |
That "1" is not a match count, it is an address (line number). What's the first line of the file ?.
|
@ syg00 -- Aha! So I *AM* doing this wrong after all.
You ask what's the first line of the file? You mean the line's contents? At this moment, the first line reads: # # THE REAL ONE! |
awk
Code:
# more file |
Conceptually I prefer the latter, however in the case of the target line not being the first line, data will be lost. Slight modification perhaps ?
Code:
awk '/#STUB/ && !m{sub("#STUB","new");m+=1}1' file |
Quote:
|
As per post #7 from the OP:
Code:
# # THE REAL ONE! |
sorry, so what should be the output of your example? i don't understand post #7, all i did understand is OP want to change only the first instance of "STUB". pls correct me again if i am wrong.
Code:
$ awk '/#STUB/ && !m{sub("#STUB","new");m+=1}1' file |
True - but that is my adjustment to your code, not your original offering ...
|
to change only the first match, you have to add the quit command like
Code:
sed -i '/pattern/{ s/.../.../; q; }' file |
Hmmm - did you test that ?.
I'm a big fan of sed, but use the right tool for the job. Personally I'd probably use perl, but I'm happy to continue to get my meagre awk knowledge improved by ghostdog74 and a couple of others on this list. |
OK, first, thanks for the continued input everyone! I took a leave last night when Star Wars came on the TV at midnight..
Personally, I feel that sed *is* the right tool for this job, but I just haven't got it quite right yet :scratch: and, of course, maybe AWK is better for this, and I just don't know it yet. Given what sed can do, I just don't understand why it won't do this properly. So, I have not *yet* tried the AWK ideas here, because I want to use sed and/or rule it out as an option. For the record/clarification, here's a better representation of what the target file looks like: Code:
data... Code:
sed -i "/#PATTERN$/ {s/^\#PATTERN$/$replacement/; q;}" $file At least I have learned one way to use the 'q' option. Maybe moving the 'q' around will help.. Still at it. Sasha |
Quote:
Code:
sed -e "/^#PATTERN$/{x;s/././;x;t;s/^#PATTERN$/$replacement/;h}" data |
How do I match only the first occurrence of a pattern?
I too think sed is the better tool, as it's a just a simple line match and substitution. You just need to know how to do it right. Code:
sed '0,/^#STUB$/ s//#FOO/' |
@ David.The.H -- Thank you,
You know, I have that very link open already (and a few others too), yet for some reason, missed that part (or subconsciously neglected to pay attention to it :/). I will be trying it as soon as I finish working on this OTHER part of the same program. Hopefully it will work, as it is simpler than awk too. Meanwhile, I had come up with another solution, which I may now (probably will) toss in favor of this method. What I came up with, was to simply have only ONE of the pattern line in the target file; so the sed operation would find that line, and replace it with the new data PLUS a newline PLUS a new pattern line, so that future operations would work. Like so: replace: #STUB with: New data blah blah blah\n#STUB It works great; only questionable thing with it is that, if for some reason Joe User decides to create multiple copies of the #STUB target line in his copy of the target file, then I'm half-way back to the start of this all; multiple replacements will get made. So, by switching to the 0, method you gave, I will be assured the replacement will only happen once, regardless. I'll update again later on this. Thanks again to everyone who helped out here, Sasha |
The things you learn - didn't know about that: thank you @David the H. GNU sed has many niceties that aren't available everywhere - I have a *very* non-GNU sed requirement sometimes. Hence my desire for other solutions rather than resorting to figuring out ugly hacks as per @osor.
|
Quote:
Quote:
|
In this case, for the record, speed is a factor in considering which tool I use.
I have replaced dozens of awk operations in this program with `sed` or `tr` equivalents, because my testing showed that sed is usually faster than awk when doing relatively simple text substitutions, and tr is probably faster than both, but the difference was immeasurable in my testing. I still have not yet tried the 0, method with sed in this particular scenario; other work has been keeping me busy. But I will update when I do try it. Sasha |
FWIW, my testing on (really) big files showed perl faster than sed - most surprised was I.
Maybe if you can consolidate a lot of those calls into one (perl ???) you'll save even more in the "setup/teardown" overheads of lots of small calls. |
Quote:
|
All times are GMT -5. The time now is 02:54 AM. |