Run on all files in a directory, treating each sep

2020-07-27 05:54发布

问题:

I want to run an AWK script on each file in a directory, but the AWK command must run only within that file - that is, it searches between a defined RS and returns what it is supposed to, but I need it to stop when it reaches the end of one file, and begin again at the start of the next file.

I have this running which works on each file individually:

awk '!/value1|value2/ && NF {print FILENAME " - " RS,$1}' RS="value" file1 > result.txt

But the output isn't correct, say, when applying it to each file in a directory using

find . -type f | awk ... file1 > result.txt

How would I get it to look at each file individually, but append the results into the same file? I have no idea unfortunately. I guess it's by adding each file into a variable and having AWK look at that, but I am not sure how to do it.

File file1:

interface Vlan3990
 ip address 172.17.226.23 255.255.255.254

File file2:

version 12.2
ip tacacs source-interface Loopback99
ip vrf test
 description xx
interface Loopback99
 description Management Loopback
interface Loopback100
 shutdown

Output

find . -type f | xargs awk '!/description|shutdown/ && NF {print FILENAME " - " RS,$1}' RS="interface" | more
./file1 - interface Vlan3990
./file2 - interface version

I am not sure where the output 'interface version' is coming from...

回答1:

Try this, given your 2 posted input files:

$ gawk '
    function prtName() {
        if (name)
            print FILENAME, name
        name=""
    }
    /^interface/                { prtName(); name=$0 }
    /^ (description|shutdown)/  { name="" }
    ENDFILE                     { prtName() }
' file1 file2
file1 interface Vlan3990

Is that what you're looking for? Note that it's gawk-specific (courtesy of ENDFILE) which I assume is fine since the sample command you posted is also gawk-specific but if that's an issue just add a test for FNR==1 and change ENDFILE to END:

$ awk '
    function prtName() {
        if (name)
            print filename, name
        name=""
    }
    FNR==1                      { prtName(); filename=FILENAME }
    /^interface/                { prtName(); name=$0 }
    /^ (description|shutdown)/  { name="" }
    END                         { prtName() }
' file1 file2
file1 interface Vlan3990


回答2:

For just the current directory:

for file in *
do awk ... "$file"
done > result.txt

If you need to recurse into subdirectories:

find . -type f -exec awk ... {} ; > result.txt

In both cases, you should probably put result.txt in a different directory. Otherwise, it will be matched and used as an input file. Or use a wildcard that only matches the desired files, and doesn't match result.txt.