Home > front end >  Grep for pattern exclusive of matching pattern if at start of line
Grep for pattern exclusive of matching pattern if at start of line

Time:01-19

I want to grep through a file of files, with path, for arbitrary patterns (given at runtime)

The problem is that I do NOT want to match those arbitrary patterns if they're in the "library path" portion of the line. But not all lines start with the library path.

I.E. given a file:

/other/more.mp3
/home/more/Music/more.mp3
/home/more/Music/Music.mp3
/home/more/Music/something other.mp3
/home/more/Music/other/something.mp3

and a "library" path of "/home/more/Music"

The pattern "Music" should match only line 3. The pattern "more" should match lines 1 and 2, but not 3. The pattern "other" should match lines 1,4, and 5.

Things I've tried:

^\($LIBRARY\)\ .*$PATTERN
^\($LIBRARY\).*$PATTERN

I could pre-process the file to remove $LIBRARY and re-add it after, probably by finding the matching line in the original file. But that seems a bit excessive, surely there's a simpler way?

CodePudding user response:

awk is more suited for this job than grep.

awk -v pat='more' -v lib='/home/more/Music' '{
         s = $0; sub("^" lib, "", s)} s ~ pat' file

/other/more.mp3
/home/more/Music/more.mp3

# or else
awk -v pat='other' -v lib='/home/more/Music' '{
         s = $0; sub("^" lib, "", s)} s ~ pat' file

/other/more.mp3
/home/more/Music/something other.mp3
/home/more/Music/other/something.mp3

# or else
awk -v pat='Music' -v lib='/home/more/Music' '{
        s = $0; sub("^" lib, "", s)} s ~ pat' file

/home/more/Music/Music.mp3

Alternative gnu grep solution:

lib='/home/more/Music'

# test 1
grep -ioP "^(?>$lib|).*more" file

/other/more
/home/more/Music/more

# test 2
grep -ioP "^(?>$lib|).*other" file

/other
/home/more/Music/something other
/home/more/Music/other

# test 3
grep -ioP "^(?>$lib|).*Music" file

/home/more/Music/Music

Note the use of atomic group in this regex, which is required to make sure we always match $lib at the start when it is there.

RegEx Demo

CodePudding user response:

the most basic form of ERE suffices -

___='/home/more/Music/'

for __ in Music more other; do

    echo "\n :: $__ ::\n\n$( 

        echo '/other/more.mp3
              /home/more/Music/more.mp3
              /home/more/Music/Music.mp3
              /home/more/Music/something other.mp3
              /home/more/Music/other/something.mp3' | 

        {m,g,n}awk      '$NF ~ __'  FS="^$___" __="$__"
                                                       -- or --
        {m,g,n}awk 'index($NF, __)' FS="^$___" __="$__"

    )\n"

done | gcat -b

——

 1   :: Music ::

 2  /home/more/Music/Music.mp3


 3   :: more ::

 4  /other/more.mp3
 5  /home/more/Music/more.mp3


 6   :: other ::

 7  /other/more.mp3
 8  /home/more/Music/something other.mp3
 9  /home/more/Music/other/something.mp3
  • Related