0

Scenario

I'm looking for lines that have contain "screenshot" that are not commented out.

Ideas

  • My original idea was to use a negative lookahead but that's not working with my grep command
  • My next idea was to look for lines that contain ^[\sa-z0-6\.]+screenshot which would make sure no instance of // or /* exist before the await page.screenshot but it seems like brackets aren't working either
  • currently only grep -E '^\s+await page.screenshot' test/*.js is working

Question

How can I make sure brackets work with my regex pattern eg ^[\sa-z0-6\.]+screenshot ?

**Edit**

I'm using grep as part of a jest pre-commit test. Here's is example code from one of the puppeteer tests

    test('content group should be closed in 2.12up', async () => {
        // const about = await page.waitForSelector(`${pageObjects.primaryNavLink}:nth-child(2)`);
        // about.click();
        // await page.waitFor(50);

        // await page.waitForSelector(`${pageObjects.secondaryFactory} .api-link`);

        const contentGroup = await page.waitForSelector(pageObjects.contentGroup);
        const boundingBox = await contentGroup.boundingBox();

        // const mc = await page.waitForSelector('.main-container');
        // console.log(mc);

        // await page.screenshot({ path: 'test/screenshots/212post.png' });

        expect(boundingBox['width']).toBeLessThanOrEqual(1);
    });

So if the grep finds any instances of page.screenshot that are not commented out, my grep based test needs to fail. Once I figure it out with the screenshots then I'm going to write a test that does the same but checks the source javascript files for any uncommented console.log instances

Finished Product

for those interested - jest test

import "core-js/stable";
import "regenerator-runtime/runtime";

const cp = require('child_process');

describe('index.html', () => {
    // test.todo('make sure there are no uncommented console messages')
    test('make sure there are no uncommented console logs', async () => {
        const cmd = `grep -P --exclude=serviceWorker.js '^(?:(?!//).)*console.log' src/*.js`;
        let grep = '';

        try {
            grep = cp.execSync(cmd);
            // console.log(grep.toString())
        } catch (err) {
            // console.log(err)
        }

        expect(grep.toString()).toEqual('');
    });

    test('make sure no screenshots are uncommented', async () => {
        // screenshot refs will cause cicd build to fail
        const cmd = `grep -P '^(?:(?!//).)*page.screenshot' test/*.test.js`;
        let grep = '';

        try {
            grep = cp.execSync(cmd);
            // console.log(grep.toString())
        } catch (err) {
            // console.log(err)
        }

        expect(grep.toString()).toEqual('');
    });
});
5
  • You really need to provide some sample input and tell which lines should be matched, and which ones not. What does commented out mean here? What language syntax is it? You mention /* and //, so is it C code you're processing?
    – ilkkachu
    Commented Aug 26, 2020 at 20:57
  • @ilkkachu I'm searching for uncommented javascript code. I added some js jest+puppeteer test code below with additional information.
    – Jacksonkr
    Commented Aug 26, 2020 at 21:04
  • Is this GNU grep or POSIX grep? Commented Aug 26, 2020 at 21:58
  • 2
    Would you need to handle const thing = "//"; await page.screenshot? Commented Aug 26, 2020 at 22:00
  • 2
    Assuming \s is whitespace, try using [:space:] instead.
    – muru
    Commented Aug 27, 2020 at 4:28

2 Answers 2

3

Several grep implementations have a -P option that allows you to use Perl-like regular expression and in particular perl's negative look ahead (?!...) operator.

So with those, to look for screenshot occurrences that are not found after //, you can do:

grep -P '^(?:(?!//).)*screenshot'

There's no \s in standard basic regular expressions. Inside a bracket expressions, [\s] is required by POSIX to match on either \ or s. Outside, the behaviour is unspecified which has allowed some grep implementations like recent versions of GNU grep to give it a similar meaning as it has in perl (the equivalent of the standard [[:space:]]).

Here, you could also use the real thing and do:

perl -ne 'print if s|//.*||r =~ /screenshot/'

For completeness, the ast-open implementation of grep has a -X option for augmented regexps. And those regexps do have a ! negation operator. So there, you can also do:

grep -X '^(.*//.*)!screenshot'

With sed, you could also remove the comments after having made a copy of the pattern space into the hold space before checking for the presence of screenshot:

sed 'h;s|//.*||;/screenshot/!d;g'

With awk:

awk -F // 'index($1, "screenshot")'

(index() for substring check, use $1 ~ /screenshot/ for (extended) regex matching).

With the field separator set to //, $1 is the part before //.

3

The \s does not works inside brackets. For example,
echo " screenshot" | grep -E "^\sscreenshot" works, but
echo " screenshot" | grep -E "^[\s]screenshot" doesn't work.

So, instead of ^[\sa-z0-6\.]+screenshot, you can use either
echo "await page.screenshot" | grep -E "^([a-z0-6.]|\s)+screenshot" or
echo "await page.screenshot" | grep -E "^[a-z0-6.[:space:]]+screenshot".

For your complete command, you want to see the lines with screenshot not inside a comment, it means if you find a /, you want neither / or * after it. You can try this:

echo "//page 1.screenshot
page 2.screenshot
foo; //page 3.screenshot" | grep -E "^([^/]|/[^/*])*/?screenshot"

output:

page 2.screenshot
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .