parsley93
parsley93

Reputation: 7

Removing file in mutliple directory with specific line

I've got tree of folders like:

00 -- 0
   -- 1
   ...
   -- 9
 ...
99 -- 0 
   -- 1
   ...
   -- 9

In every folder I have .ini files with some kind od text.

How can I remove files which got # at beginning of second line?

I tried to use:

for i in {00..99}; do for b in {0..9}; do grep -LZ -- # *.ini | xargs
-r0 rm; done; done

but it didn't works. I wonder about using sed and awk to do it, but i don't know how.

Upvotes: 0

Views: 35

Answers (1)

tripleee
tripleee

Reputation: 189327

With a recent enough Awk and GNU find you can do

awk 'FNR==2 { if ($0 ~ /^#/) printf "%s\0", FILENAME; nextfile }' [0-9][0-9]/[0-9]/*.ini |
xargs -r0 echo rm

The nextfile statement is a POSIX extension but might not be present in very old Awk implementations. If your files are small, maybe just take out the nextfile and live with the minor inefficiency that we read through the end of each file even though we only really need to examine the second line.

The -0 option to xargs is a GNU extension. If your file names are guaranteed to not contain newlines, you can probably get away with

awk 'FNR==2 { if ($0 ~ /^#/) print FILENAME; nextfile }' [0-9][0-9]/[0-9]/*.ini |
xargs -r echo rm

Finally, remove the echo to actually remove the files it prints.

In some more detail, Awk processes each input file one line at a time, and evaluates the script on each separately. The built-in variable FNR is set to the current line number within the file, and FILENAME is the current file's name. The variable $0 contains the entire line, and we check whether it matches the regular expression ^# (beginning of line, immediately followed by a literal # character); if so, we print the FILENAME(otherwise, no output for this file). The nextfile command closes the current file and skips directly to the first input line of the next file in the argument list (or stops processing if no file names remain to be processed).

If you have a lot of matching files, you can't use a wildcard like that (you get "argument list too long"); if so, maybe simply revert back to the loop you had.

The immediate error in your attempt is that you need quotes around # (otherwise, it marks the rest of the line as a comment); but of course, your grep looks for that character anywhere in the file, and you didn't specify the path for the file to examine. With the immediate errors fixed, that would be

# Don't use, still broken
for i in stuff; do
    for b in more stuff; do
        grep -LZ '#' "$i/$b"/*.ini
    done
done |
# or simply grep -LZ '#' [0-9][0-9]/[0-9]/*.ini
xargs -r0 echo rm

but again, you can't easily fix this to only look at the second line of each file. (Notice also how I run the final xargs outside the final done.)

Upvotes: 1

Related Questions