17

I recently wrote a script that does a sed command, to replace all the occurrences of "string1" with "string2" in a file named "test.txt".

It looks like this:

sed -i 's/string1/string2/g' test.txt

The catch is, "string1" does not necessarily exist in test.txt.

I notice after executing a bunch of these sed commands, I get a number of empty files, left behind in the directory, with names that look like this:

"sed4l4DpD"

Does anyone know why this might be, and how I can correct it?

kronn
  • 925
  • 11
  • 31
Toast
  • 356
  • 1
  • 2
  • 8
  • 2
    Does this happen when you don't use the `-i` option? – Michał Wojciechowski Oct 12 '11 at 00:16
  • Don't you need the -e flag to treat the `s/.../.../g` argument as a script? – Oscar Korz Oct 12 '11 at 00:42
  • 3
    @okorz001: No, the `-e` option is not necessary here. – Keith Thompson Oct 12 '11 at 01:26
  • How does the number of these files compare to the number of sed commands you executed? How does it compare to the number of files which do or don't contain "string1" (I suspect that's irrelevant). What OS are you on? Does sed report that it failed (check `$?` in bash, or `$status` in tcsh)? If you have the `strace` command, try using it: `strace -o sed.strace sed ...`; it will show you the arguments and results of the system calls. Look for a failing `write()` or `rename()` call. – Keith Thompson Oct 12 '11 at 01:37

4 Answers4

15

-i is the suffix given to the new/output file. Also, you need -e for the command.
Here's how you use it:

sed -i '2' -e 's/string1/string2/g' test.txt

This will create a file called test.txt2 that is the backup of test.txt

To replace the file (instead of creating a new copy - called an "in-place" substitution), change the -i value to '' (ie blank):

sed -i '' -e 's/string1/string2/g' test.txt

EDIT II

Here's actual command line output from a Mac (Snow Leopard) that show that my modified answer (removed space from between the -i and the suffix) is correct.
NOTE: On a linux server, there must be no space between it -i and the suffix.

> echo "this is a test" > test.txt
> cat test.txt
this is a test
> sed -i '2' -e 's/a/a good/' test.txt 
> ls test*
test.txt    test.txt2
> cat test.txt
this is a good test
> cat test.txt2
this is a test
> sed -i '' -e 's/a/a really/' test.txt 
> ls test*
test.txt    test.txt2
> cat test.txt
this is a really good test
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • That's not correct. The argument to `-i` must immediately follow the `-i`; it can't be a separate argument. With just `-i`, the file is updated in place (in effect; sed internally uses a temp file). The command in the original question is correct. It's failing for unknown reasons. (I'm assuming GNU sed, but it's probably the same for other sed implementations.) – Keith Thompson Oct 12 '11 at 01:28
  • @Keith Thompson Please read update. What can I say... I'm correct. – Bohemian Oct 12 '11 at 06:36
  • Are you sure about that? For GNU sed (as of version 4.2.1), the syntax is "-i[SUFFIX], --in-place[=SUFFIX]"; `-i ''` doesn't even work. On Solaris 9, /usr/bin/sed doesn't even have a `-i` option. POSIX doesn't specify a `-i` option. What version and OS are you using? – Keith Thompson Oct 12 '11 at 06:36
  • I see that sed does behave the way you describe on MacOS; here's the [man page](http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/sed.1.html). But you said it was a "linux command line output". Can you clarify? – Keith Thompson Oct 12 '11 at 06:46
  • Yes, it was done on a Mac. I just run it on one of our (real) linux servers (GNU/Linux) and you're right - it needs to be `-i'2'` (no space). I then tried the "no space" version on my Mac, and it also works. That is, both `-i'2'` and `-i '2'` (no space and with space) work the same on the Mac – Bohemian Oct 12 '11 at 10:06
  • And `-i` with no argument overwrites the input file (by creating an renaming a temp file). Your answer still doesn't say that the suffix is optional for GNU sed, but it's more consistent so I've removed my downvote. – Keith Thompson Oct 12 '11 at 17:17
5

I wasn't able to reproduce this with a quick test (using GNU sed 4.2.1) -- but strace did show sed creating a file called sedJd9Cuy and then renaming it to tmp (the file named on the command line).

It looks like something is going wrong after sed creates the temporary file and before it's able to rename it.

My best guess is that you've run out of room in the filesystem; you're able to create a new empty file, but unable to write to it.

What does df . say?

EDIT:

I still don't know what's causing the problem, but it shouldn't be too difficult to work around it.

Rather than

sed -i 's/string1/string2/g' test.txt

try something like this:

sed 's/string1/string2/g' test.txt > test.txt.$$ && mv -f test.txt.$$ test.txt

Something is going wrong with the way sed creates and then renames a text file to replace your original file. The above command uses sed as a simple input-output filter and creates and renames the temporary file separately.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Running 'df .' says I've only used 8% of the space (which is about 150GB). – Toast Oct 12 '11 at 00:41
  • http://stackoverflow.com/questions/1823591/sed-creates-un-deleteable-files-in-windows look similar. Are you on Windows? – Keith Thompson Oct 12 '11 at 01:22
  • The command is being run on a server running Suse Linux. It seems that the commands are executing successfully, but with the high volume of substitutions taking place, it would be hard for me to be sure (without writing another script). – Toast Oct 12 '11 at 03:02
  • **For permission errors** on in place replace, with a temp file, see http://stackoverflow.com/questions/20146239/how-to-set-temp-file-directory-for-sed-command-in-linux/40030663#40030663 – storm_m2138 Oct 13 '16 at 21:30
4

So after much testing last night, it turns out that sed was creating these files when trying to operate on an empty string. The way i was getting the array of "$string1" arguments was through a grep command, which seems to be malformed. What I wanted from the grep was all lines containing something of the type "Text here '.'".

For example the string, "Text here 'ABC.DEF'" in a file, should have been caught by grep, then the ABC.DEF portion of the string, would be substituted by ABC_DEF. Unfortunately the grep I was using would catch lines of the type "Text here ''" (that is, nothing between the ''). When later on, the script attempted to perform a sed replacement using this empty string, the random file was created (probably because sed died).

Thanks for all your help in understanding how sed works.

Toast
  • 356
  • 1
  • 2
  • 8
-5

Its better if you do it in this way:

cat large_file | sed 's/string1/string2/g' > file_filtred

nullck
  • 37
  • 2
  • 3
    The `cat` command is unnecessary. `sed` can read the file directly as per the question. More importantly, this answer doesn't attempt to answer the actual question that was asked. – Anthony Geoghegan Jan 21 '16 at 18:03