Join 3,375 readers in helping fund MetaFilter (Hide)


No tengo sed?
May 29, 2012 9:10 PM   Subscribe

Trying to find-and-replace text within a file, using the Terminal on Mac OS X 10.7.4. Can't for the life of me get it to work. Please help.

I'm doing this in the command line because it's part of a loop in a bash script, but I can't get this to work on even one file at a time. You can download an example file at The extension is kinda weird but it's just a text file.

Here's the code I'm trying:
sed 's/BACKGROUND_FILL = ( 0 )/BACKGROUND_FILL = ( 200 253 )/' example_file.hdr

Here's the command-line output I get:


6371007.181000000 0.000000000 0.000000000
0.000000000 0.000000000 0.000000000
0.000000000 0.000000000 0.000000000
0.000000000 0.000000000 0.000000000
0.000000000 0.000000000 0.000000000 )


# Corner point values refer to the outer extent of the pixel
UL_CORNER_LATLON = ( 9.999999999 177.223209877 )
UR_CORNER_LATLON = ( 9.999999999 -172.622524005 )
LL_CORNER_LATLON = ( 0.000000000 -179.999999984 )
LR_CORNER_LATLON = ( 0.000000000 -169.999999985 )

# UL_CORNER_XY = ( -20015109.353999998 1111950.519667000 )
# UR_CORNER_XY = ( -18903158.834332995 1111950.519667000 )
# LL_CORNER_XY = ( -20015109.353999998 0.000000000 )
# LR_CORNER_XY = ( -18903158.834332995 0.000000000 )

BANDNAMES = ( Percent_Tree_Cover )
NLINES = ( 4800 )
NSAMPLES = ( 4800 )
PIXEL_SIZE = ( 231.656358263958 )
MIN_VALUE = ( 0 )
MAX_VALUE = ( 0 )
BACKGROUND_FILL = ( 200 253 )


BYTE_ORDER = little_endian

Looks great! But when I look at the file, nothing has changed (the BACKGROUND_FILL line is as it was before) and the "file modified" date hasn't changed.

Please help me figure out what I'm doing wrong. Thanks in advance.
posted by dondiego87 to Computers & Internet (6 answers total)
You just need to redirect the output to a new file:

sed 's/BACKGROUND_FILL = ( 0 )/BACKGROUND_FILL = ( 200 253 )/' example_file.hdr > output

See here for some more info.
posted by cuetip at 9:11 PM on May 29, 2012

To be clear, then you'll have a new file called "output" that has what was earlier being printed out.
posted by cuetip at 9:12 PM on May 29, 2012

sed might do in-place editing too, depends on the flavor and version of sed on OS X, it's usually the '-i' option. Perl will do it with a backup of the original.

$ perl -pi.bak -e 's/\QBACKGROUND_FILL = ( 0 )/BACKGROUND_FILL = ( 200 253 )/' example_file.hdr

$ fgrep BACKGROUND_FILL example_file.hdr*
example_file.hdr:BACKGROUND_FILL = ( 200 253 )
example_file.hdr.bak:BACKGROUND_FILL = ( 0 )

That goes '-p' print each line, '-i.bak' in-place edit keeping a backup file with a '.bak' extension, '-e' execute/eval this code. The '\Q' in the regex turns on quotemeta so you don't have to escape the '()' special characters. If you don't want a backup file, just don't provide an extension to '-i', i.e.: perl -pi -e 'code'.
posted by zengargoyle at 11:00 PM on May 29, 2012 [1 favorite]

As others have said, sed (the Stream EDitor) reads from standard in and writes to standard out by default (as do a large portion, if not most, unix tools). GNU sed and possibly others have the -i flag that zengargoyle mentioned to do in-place editing, but that's not a universal option, so YMMV.
posted by namewithoutwords at 5:38 AM on May 30, 2012

sed works just like cat, and many other unix-y command line tools. They don't open a file, modify it and then save it like a GUI app does. Instead, they are like filters. They work on streams of data. Unless you specify differently, they take their input from the standard input (keyboard) and put their output onto the standard output (screen).

You can try for yourself by just going into terminal and entering cat. Instead of giving you back a prompt, you just get a cursor. Each line you type (hitting enter after) will just be output back to the screen. (control-c to exit) You could type cat > filename and the same thing would happen, but instead of repeating each line on the screen, it would put each line you type into that filename.

So, you've given it a filename to work with, but haven't told it where to send the output, so its outputting to the screen.

(This seems stupid and archaic, but it is actually quite powerful once you get your mind wrapped around it. Because besides outputting things to files, you can output them to devices (which act like files in the unix way). Or you can pipe them through other tools.)

So yeah, you want to do sed [options] [input filename] > [output filename]. In a batch file like this, you wouldn't want to output it right onto the same filename, because the first line of output would overwrite the file that is still being used to feed sed. So you can just mv [new filename] [original filename] after the sed statement.
posted by gjc at 5:57 AM on May 30, 2012

Looks like BSD sed (which will be the one your Mac uses) does have the -i option available.

Also, good sed practice is to use its line addressing features to select the lines you're applying your substitute commands to, rather than applying a possibly-inapplicable substitution to every single line as you're doing here. Of course on modern computer you would never even see the speed difference, but here's what I'd use anyway just for good form's sake:
sed -i.bak -e '/^BACKGROUND_FILL = /s/( 0 )/( 200 253 )/' example_file.hdr

posted by flabdablet at 10:31 AM on May 30, 2012

« Older Pre-tenure life: what are your...   |  Pregnant in a termite infested... Newer »
This thread is closed to new comments.