MultipleFiles

Version warning

Some of these techniques will require non-ancient versions of awk.

How can awk test for the existence of a file?

The most portable way to test for the existence of a file is to simply try and read from the file.

        function exists(file,        dummy, ret)
        {
                ret=0;
                if ( (getline dummy < file) >=0 )
                {
                        # file exists (possibly empty) and can be read
                        ret = 1;
                        close(file);
                }
                return ret;
        }

[ I've read reports that earlier versions of mawk would write to stderr as well as getline returning <0 -- is this still true? ]

On Unix, you can probably use the `test' utility

        if (system("test -r " file) == 0)
            # file is readable
        else
            # file is not readable

Edit this answer

How can I get awk to read multiple files?

awk automatically reads multiple files (under Unix at least) -- use something like:

    awk '/^#include/ {print $2}' *.c *.h

Edit this answer

How can I tell from which file my input is coming?

the file name is stored in the built-in variable FILENAME:

    awk '/^#include/ {print FILENAME,$2}' *.c *.h

Edit this answer

How can I get awk to open multiple files (selected at runtime)?

You can open files dynamically using `getline', `close', and `print EXPR > FILENAME', like:

    # assumes input file has at least 1 line, output file writeable
    function double(infilename,outfilename,    aline)
    {
      while ( (getline aline < infilename) >0 )
        print(aline aline) > outfilename;
      close(infilename);
      close(outilename);
    }

Edit this answer

How can I treat the first file specially?

you can tell if awk is parsing the first file given on the command line using FILENAME, thusly:

    BEGIN { rulesfile="" }
    rulesfile == "" { rulesfile = FILENAME; }
    FILENAME == rulesfile { build_rule($0); }
    FILENAME != rulesfile { apply_rule($0); }

Example:

Suppose you have a text-line "database" and you want to make some batch changes to it, by replacing some old lines with new lines.

    BEGIN { rulesfile="" }
    rulesfile == "" { rulesfile = FILENAME; }
    rulesfile == FILENAME { replace[$1] = $0; }
    rulesfile != FILENAME \
    { 
            if ($1 in replace) 
                    print replace[$1];
            else
                    print;
    }

Another way, using ARGV:

    (FILENAME == ARGV[1]) { replace[$1] = $0; next }
    ($1 in replace) { print replace[$1]; next }
    { print }

Edit this answer

How can I explicitly pass in a filename to treat specially?

You can use `-v rulesfile=filename' to process a file differently, like you would any other variable, and then use a `getline' loop (and `close') in your BEGIN statement.

    BEGIN \
    {
      if (rulesfile=="")
      {
        print "must use -v rulesfile=filename";
        exit(1);
      }
      while ( (getline < rulesfile) >0 )
        replace[$1]=$0;
      close(rulesfile);
    }

    {
      if ($1 in replace)
        print replace[$1];
      else
        print;
    }

Edit this answer