How do I iteratively replace lines in a file?

Kai Meyer kai at unixlords.com
Sun Mar 20 12:39:13 PDT 2011


On 03/20/2011 09:46 AM, Andrej Mitrovic wrote:
> Yeah, I've already done exactly as you guys proposed. Note however
> that `inputfile` and `outputfile` should be declared inside the
> foreach loop. Either that or you have to call `close()` explicitly. If
> you don't do that, file handles don't get released, and you'll
> eventually get back a stdio error such as "too many file handles
> opened". You could loose files this way. I know this because it just
> happened yesterday while testing. :p
>
> Anywho, I needed a quick script to append a semicolon to import lines
> because I managed to screw up some files when using sed to replace
> some lines. It's a quick hack but worked for me:
>
> import std.stdio;
> import std.file;
> import std.stdio;
> import std.path;
> import std.string;
>
> void main()
> {
>      File inputfile;
>      File outputfile;
>      string newname;
>
>      foreach (string name; dirEntries(r".", SpanMode.breadth))
>      {
>          if (!(isFile(name)&&  getExt(name) == "d"))
>          {
>              continue;
>          }
>
>          newname = name.idup ~ "backup";
>          if (exists(newname))
>          {
>              remove(newname);
>          }
>
>          rename(name, newname);
>
>          inputfile = File(newname, "r");
>          outputfile = File(name, "w");
>
>          foreach (line; inputfile.byLine)
>          {
>              if ((line.startsWith("private import") ||
> line.startsWith("import"))&&
>                  !line.endsWith(",")&&
>                  !line.endsWith(";"))
>              {
>                  outputfile.writeln(line ~ ";");
>              }
>              else
>              {
>                  outputfile.writeln(line);
>              }
>          }
>
>          inputfile.close();
>          outputfile.close();
>      }
>
>      foreach (string name; dirEntries(r".", SpanMode.breadth))
>      {
>          if (getExt(name) == "dbackup")
>          {
>              remove(name);
>          }
>      }
> }


Funny, I would have just fixed it with sed.

sed -ir 's/^(import.*)/\1;' *.d

Infact, I think sed is actually a great example of an application that 
you apply a search and replace on a per-line basis. I'd be curious if 
somebody knows how their '-i' flag (for in-place) works. Based on the 
man page, I'll bet it opens the source read-only, and opens the 
destination write-only like Andrej's example.
        -i[SUFFIX], --in-place[=SUFFIX]
               edit files in place (makes backup if extension supplied)

The SUFFIX option just renames the original instead of deleting at the end.


More information about the Digitalmars-d-learn mailing list