Unix/Linux
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
 
User Name:
Password:
Remember me
Go Back   Web Development Archives FAQs Unix/Linux

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Display Modes
 
Unread Web Development Archives Sponsor:
  #1  
Old July 3rd, 2008, 06:30 AM
Dave B
Guest
Dev Archives Newbie (0 - 499 posts)
 
Posts: n/a  
Time spent in forums:
Reputation Power:
Use sed to modify a line in a file, *without* duplicating thefile

Ch. Konig wrote:

Hi there
>

I just have to modify a single line in a file. I know how to do that
using sed like:
sed "s/searchpattern/newexpression/" oldfile newfile
>

My "problem" is that I always have to duplicate that file, i.e. I have
to follow it by sth like
/bin/mv -f newfile oldfile
>

Firstly, my files can be quite large, so that can become heavy.
Secondly, I sometimes have to make several changes, so either I make
many files (a new temp file for each change) or I do a mv -f after
each change. (I know I can do several changes with one sed command,
but it's in a script, so I find it easier to do them individually.)
>

I feel there must be a more direct way to do that, but I haven't found
it. Thanks a lot for any advice.

GNU sed has an option -i, which lets you modify the file "in place" (of
course it creates a temp file, but it's all handled by sed and you don't
have to do anything.
Then, using a single sed script to do many changes at once, albeit seemingly
more difficult (which it actually isn't), is much more efficient than
running sed many times, each time making a pass over the entire file.

--
echo 0|sed 's909=#3u)o19;s0#0ooo)];s()(0bu}=(;s#}#.1m"?0^2{#;
s)")9v2@3%"9$);so%op]t(p$e#!o;sz(z^+.z;su+ur!z"au;sxzxd?_{h)cx;:b;
s/\(\(.\).\)\(\(\)*\)\(\(.\).\)\(\(\)\6.*\2.*\)/\5\3\1\7/;
tb'|awk '{while((i+=2)<=length($1)-18)a=a substr($1,i,1);print a}'

Reply With Quote
  #2  
Old July 4th, 2008, 06:39 AM
Dave B
Guest
Dev Archives Newbie (0 - 499 posts)
 
Posts: n/a  
Time spent in forums:
Reputation Power:
Use sed to modify a line in a file, *without* duplicating the?file

Ch. Konig wrote:

Now that's a tease. I thought sed would be obscure enough, but you
through ed at me. Google is astonishingly silent on the whole ed
script front, or there are too many Ed's (people of that name) out
there diluting the results. Back to the subject.
>

I played around with writing some edscripts. The problem with output
from 'diff -e' is that it's line based, while I'm looking for a
pattern (in my case a variable name) to replace (resp. to change its
assigned value). The second bother is that ed needs scripts with
several lines (true?) while I want to keep it a one-liner.
>

What works now is this:
>

(echo ",s/par1/par1\ =\ 7.00e+04/"; echo w) | ed -s mod2
>

This will look for where par1 is assigned (there's random number of
spaces in between and some assigned value after) and replace it with
an assignment of some value that I choose (7.00e+04 in this case).
>

Not extremely elegant, but it does the trick and modifies the file in-
place.

Please note that, for global modifications (ie, the "," address), ed scans
the whole file for each command, so if you have many changes to do it's very
inefficient and almost equivalent to running sed many times over the same
file. As an extreme example, consider a ~1000000 lines file, where you want
to perform the following substitutions:

s/foo/bar/g
s/baz/blah/g

With sed:

$ time sed -i 's/foo/bar/g;s/baz/blah/g' bigfile

real 0m14.437s
user 0m5.700s
sys 0m8.730s


With ed:

$ time (echo ',s/foo/bar/g'; echo ',s/baz/blah/g'; echo 'w') | ed -s bigfile

real 0m31.734s
user 0m12.600s
sys 0m19.050s

You should get similar result in terms of relative timings.

Furthermore, ed's man page states that, unlike in sed, "it is an error if
the substitution fails on every addressed line", so you get "?" output in
that case:

$ cat file2
1
2
3
$ (echo ',s/foo/bar/g'; echo ',s/baz/blah/g'; echo 'w') | ed -s file2
?
?
$

(not mentioning that, at least on my system, ed DES create a temp file
anyway, just like sed -i, although ed immediately unlinks the file so that
it's not visible).

a side note, awk seems to be *really*, *really* damn faster than either
sed or ed, at least in this particular test case:

$ time awk '{gsub(/foo/,"bar");gsub(/baz/,"blah")}1' bigfile newfile

real 0m2.923s
user 0m2.480s
sys 0m0.430s

--
echo 0|sed 's909=#3u)o19;s0#0ooo)];s()(0bu}=(;s#}#.1m"?0^2{#;
s)")9v2@3%"9$);so%op]t(p$e#!o;sz(z^+.z;su+ur!z"au;sxzxd?_{h)cx;:b;
s/\(\(.\).\)\(\(\)*\)\(\(.\).\)\(\(\)\6.*\2.*\)/\5\3\1\7/;
tb'|awk '{while((i+=2)<=length($1)-18)a=a substr($1,i,1);print a}'

Reply With Quote
  #3  
Old July 4th, 2008, 08:00 AM
Janis Papanagnou
Guest
Dev Archives Newbie (0 - 499 posts)
 
Posts: n/a  
Time spent in forums:
Reputation Power:
Use sed to modify a line in a file, *without* duplicating the?file

Ch. Konig wrote:
>

Can I use awk "in place"?

No, not in the way you think of.

My first trials (having 'bigfile bigfile' at the end of your script)
swalled up the whole file.

Never do that! Any program started in a shell by

any_program bigfile bigfile

will let the shell rewrite bigfile before any_program is started
to operate on bigfile which is provided as argument.

And: Does that now even matter considering even ed makes an
(invisible) copy? I.e. does any change require enough space for
duplication?

Not sure what you ask here.

It's certainly possible to make a binary or textual "patch" on a
file on disk without copying the file. But you are asking for a
substitution where in general the length of the replacement string
will differ from the replaced string. The safe approach is copying
the file before you work on it or creating a new file and moving
it to the name of the original file in case no error occurred

any_program bigfile tmpfile && mv tmpfile bigfile

You can, of course, put that code pattern in a wrapper script so
that you don't "see" the implicit temporary.

Janis

>

CK

Reply With Quote
  #4  
Old July 4th, 2008, 09:19 AM
Dave B
Guest
Dev Archives Newbie (0 - 499 posts)
 
Posts: n/a  
Time spent in forums:
Reputation Power:
Use sed to modify a line in a file, *without* duplicating the?file

Ch. Konig wrote:

>$ time awk '{gsub(/foo/,"bar");gsub(/baz/,"blah")}1' bigfile newfile
>>

>real 0m2.923s
>user 0m2.480s
>sys 0m0.430s
>>

>

Can I use awk "in place"?
>

My first trials (having 'bigfile bigfile' at the end of your script)
swalled up the whole file.

No, you can't do that with the shell, unless - *not recommended* - you play
nasty tricks - like for instance unlinking the original file and writing to
it through another descriptor. An example of such questionable practice is
doing something like

(rm file; sed file) < file

Note, however, that that command still does NT truly edit "in place". There
are still two files involved.

Generally speaking, you can however "slurp" the whole file in memory, do
what you want with the data, and then write back the whole lot to a file
with the same name. This of course comes at the price of using much memory.

With awk, you can add some code to do that, but note that the resulting
script is slower than the original (although still faster than sed):

$ time awk '{gsub(/foo/,"bar");gsub(/baz/,"blah");a[NR]=$0}
END {close(FILENAME);for(i=1;i<=NR;i++) print a[i]>FILENAME}' bigfile

real 0m8.471s
user 0m7.690s
sys 0m0.710s

And: Does that now even matter considering even ed makes an
(invisible) copy? I.e. does any change require enough space for
duplication?

Yes. The main problems with true "in place" modification are:

- what happens if something goes wrong and the operation is interrupted
halfway? (for instance in the sed example above)
- what happens if you replace a string with a longer/shorter string?

Many editors (both interactive and non-interactive), to simulate "in place"
editing, create a temporary file.

--
echo 0|sed 's909=#3u)o19;s0#0ooo)];s()(0bu}=(;s#}#.1m"?0^2{#;
s)")9v2@3%"9$);so%op]t(p$e#!o;sz(z^+.z;su+ur!z"au;sxzxd?_{h)cx;:b;
s/\(\(.\).\)\(\(\)*\)\(\(.\).\)\(\(\)\6.*\2.*\)/\5\3\1\7/;
tb'|awk '{while((i+=2)<=length($1)-18)a=a substr($1,i,1);print a}'

Reply With Quote
Reply

Viewing: Web Development Archives FAQs Unix/Linux > Use sed to modify a line in a file, *without* duplicating thefile


Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are Off
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest Threads | Shoutbox
Forum Jump


Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 





© 2003-2008 by Developer Shed. All rights reserved. DS Cluster 6 hosted by Hostway
Stay green...Green IT