Sed does not make changes in the file but to the standard output

I have an xml file.
I am doing some change, say deleting line 770. File name is file.xml. I use:

sed '770d' file.xml

but this does not actually make changes in the *file* but shows the changes on standard output (screen)

if i use

$var=`sed '770d' file.xml`
echo $var > file.xml

this makes me loose all the formatting of xml (no carriage return is inserted, instead everything is inputted in the form of a single paragraph).

sed '770d' file.xml >temp.xml
mv temp.xml file.xml

Thanks
NT

Try

sed -e 's700d' <file.xml >foo.xml
mv foo.xml file.xml

You can edit in place with perl:

perl -n -i.BAK -e 'print if $. != 700' file.xml

The original file is in file.xml.BAK

Hi.

A GNU/Linux package, moreutils, contains a few interesting utilities. Of relevance here is sponge. It sucks up data from STDIN, and spits it out to a file of your choice [default STDOUT] at EOF. This alleviates the common error of re-directing STDOUT to the original input file. It's a good general solution, but it does involve using a temporary file -- we often accept a little overhead for convenience.

Here's a demonstration driver script using cat and sed:

#!/usr/bin/env bash

# @(#) s1       Demonstrate sponge.

echo
set +o nounset
LC_ALL=C ; LANG=C ; export LC_ALL LANG
echo "Environment: LC_ALL = $LC_ALL, LANG = $LANG"
echo "(Versions displayed with local utility \"version\")"
version >/dev/null 2>&1 && version "=o" $(_eat $0 $1) perl
set -o nounset
echo

FILE=${1-data1}
SPONGE=./sponge

cp original-data $FILE
echo " Data file $FILE:"
cat $FILE

echo
echo " Results for default STDOUT:"
cat $FILE | $SPONGE

cp original-data $FILE
echo
echo " Results for re-writing $FILE:"
sed '/2/d' $FILE | $SPONGE $FILE
cat $FILE

exit 0

Producing:

% ./s1

Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 2.6.11-x1, i686
Distribution        : Xandros Desktop 3.0.3 Business
GNU bash 2.05b.0
perl 5.8.4

 Data file data1:
1
2
3

 Results for default STDOUT:
1
2
3

 Results for re-writing data1:
1
3

Not everyone wants to obtain GNU/Linux utilities, so I hacked together a perl script to do the basic job. No warranties, etc.:

#!/usr/bin/perl

# @(#) sponge   Read STDIN, write to file at EOF.

## Modification history: when / who / what: most recent at top.
#  Relocate to end if grows too long, or re-sequence.
#
# 2009.04.06 / drl / original.

use warnings;
use strict;

my ($debug);
$debug = 1;
$debug = 0;

my ( $buf, $file, $tmp, $temporary );
$file = shift || ">-";

$temporary = "/tmp/sponge_$$";
open( $tmp, ">", $temporary ) || die " Cannot open $temporary for write.\n";
print " debug write - temporary is :$temporary:\n" if $debug;
while ( read( STDIN, $buf, 16384 ) ) {
  print $tmp $buf;
}

close $tmp;
open( $tmp, "<", $temporary ) || die " Cannot open $temporary for read.\n";
print " debug read  - temporary is :$temporary:\n" if $debug;
if ( $file eq "-" ) {
  open( FILE, ">-" ) || die " Cannot open STDOUT for writing.\n" if $debug;
}
else {
  open( FILE, ">$file" ) || die " Cannot open $file for write.\n";
}
print " debug write - file is :$file:\n" if $debug;
while ( read( $tmp, $buf, 16384 ) ) {
  print FILE $buf;
}

unlink $temporary;

exit(0);

So sponge can be used for any such situation, sed, awk, grep, etc. To make effective use of sponge, you'd probably want to place it in a directory in your path, say, $HOME/bin for most users. That would eliminate the requirement of needing it in the current directory.

Kernighan and Pike addressed this issue in a slightly different way in 1978 with a script called overwrite in The UNIX Programming Environment, page 152 ff.

One possible useful modification would be to omit the temporary file if the data i short enough -- left as an exercise for the reader :slight_smile: ... cheers, drl