aymanzone aymanzone - 2 months ago 9
Linux Question

Matching file extensions inside content with grep ('*.log' is an error)

I'm trying to search each line to see which lines have any_filename.log

The below codes aren't working

find . -print | xargs grep -i *.log
find . -print | xargs grep -i "*.log"
find . -print | xargs grep -i '*.log'


does anyone know the right code?

thanks you

Answer

You don't actually need the * at all; it doesn't do anything useful here. In regex syntax (as used by grep), * means "0 or more of the immediately preceding character". When there is no preceding character, it is thus a syntax error.

By contrast, . in a regex means "match any single character". If you want to match a period, you need to escape it or put it inside a character class, like so:

find . -exec grep -i -e '[.]log' -- /dev/null '{}' +

If the line needs to end with .log, by contrast, anchor the match with a $:

find . -exec grep -i -e '[.]log$' -- /dev/null '{}' +

Notes:

  • *.log is glob syntax. [.]log$ is an equivalent pattern in regex (regular expression) syntax. These are two very different languages.
  • find ... | xargs ... is buggy (fails with filenames containing spaces, quotes, literal backslashes, etc) unless -print0 is used in find, and -0 is used with xargs. Both of these are non-POSIX extensions, so it's better to use the POSIX-compliant -exec ... {} + action in find to get the xargs behavior of running as few subprocesses as possible with names given literally.
  • The grep ... -- /dev/null idiom services two purposes: Passing /dev/null ensures that grep's defaults are those it uses when passed at least two files, even if find only invoked that particular grep instance with only a single filename. The -- flag, by contrast, ensures that all subsequent filenames are treated as names, not as flags; it's not strictly necessary when used with find in this manner (as all arguments will be preceded with ./, thus not potentially looking like optional arguments), but is good practice nonetheless.