0

Print lines consisting of a definition of a single C variable of type int, without initialization, optionally preceded by unsigned, and optionally followed by any single line // comment.

I am using

egrep "^int.*[a-zA-Z0-9].*[^=].*;|^ unsigned int.*[a-zA-Z0-9].*[^=].*;" myfile.txt

It prints

int x=9;
int dftr2;

while it does not print

int x;

and it should not print

int x=9;

Here is the content of myfile.txt

int x;
int x=9;
int dftr2;
unsigned int dftrxe2;
unsigned int w=1;

The use of egrep is compulsory.

3
  • does it have to be a single egrep command or are pipes between multiple egrep executions allowed?
    – MikeA
    Sep 12, 2016 at 23:04
  • 4
    Is this homework?
    – Thor
    Sep 12, 2016 at 23:10
  • 1
    your problem is this part .*[^=].*; because it requires the match to be at least 2 characters in length after int or unsigned int. it also does not properly exclude = as you want because .* is doing something you do not expect/understand.
    – MikeA
    Sep 12, 2016 at 23:16

3 Answers 3

3

If I take your question literally (and don’t limit myself to trying to build on your incomplete answer) I believe that the correct answer is:

egrep '^\s*(unsigned\s+)?int\s+[_A-Za-z][_A-Za-z0-9]*\s*;\s*(//.*)?$' myfile.txt

Step by step:

  • ^ to anchor the search to the beginning of the line.
  • \s* to allow any number of whitespace characters (space or tab) to occur at the beginning of the line, before the declaration.
  • (unsigned\s+)? to allow “unsigned” to appear zero or one time.
    • If it is present, it is followed by one or more spaces — \s+.
  • int\s+ matches the “int” keyword, also followed by one or more spaces.
  • [_A-Za-z] — the first character of a C variable name must be a letter or an underscore (_).
  • [_A-Za-z0-9]* — subsequent characters of a C variable name may be letters, underscores, or digits.  There may be any number of them (including zero, since we’re talking about what follows the first character).
    • (Some C compilers probably impose a maximum identifier length.  I don’t remember whether the Standard does, and I’m not going to bother looking it up.)
  • \s* to allow any number of spaces …
  • … before the ;.
  • \s* to allow any number of spaces after the semicolon.
  • (//.*)? — optionally allow a // comment, and
  • $ to anchor the search to the end of the line.

If you want, you can

  • replace \s with [[:space:]] or [SpaceTab],
    • If you’re typing this at the keyboard, you may need to type Ctrk+V and then Tab in order to get an actual tab character in the command line.  (Of course this won’t be an issue if you’re writing a script.)
  • replace [_A-Za-z] with [_[:alpha:]], and/or
  • replace [_A-Za-z0-9]* with [_[:alnum:]].

Counter-examples:

The

egrep '^(unsigned )?int [^=]*;' myfile.txt

command, shown in another answer, prints the following lines:

int a, b;               // Multiple variables declared.
int c; int d;           // Multiple “int” declarations.
int e; float f;         // Multiple declarations where only the first is an “int”.
int g[9];               // Array.
int *h;                 // Pointer.
int func();             // Function.
int 3D;                 // Illegal variable name.
int 42;                 // Not even an illegal variable name.

(which it should not print), and skips the following lines:

  int s;                // Space(s) at the beginning of the line.
int     t;              // Tab after “int”.
unsigned  int u;        // Multiple spaces after “unsigned”.
unsigned        int v;  // Tab after “unsigned”.

(which it should print).

1

This looks for lines starting with int or unsigned int for which the statement terminates with ; and does not contain =:

$ egrep '^(unsigned )?int [^=]*;' myfile.txt
int x;
int dftr2;
unsigned int dftrxe2;

Observe that this works with comments as well and correctly ignores any = in the comment. Consider this test file:

$ cat myfile2.txt
int y; // y=height
int z=1; // z is depth

This is the result:

$ egrep '^(unsigned )?int [^=]*;' myfile2.txt
int y; // y=height

Lastly, note that egrep is deprecated. grep -E is preferred:

grep -E '^(unsigned )?int [^=]*;' myfile.txt
0

Searching for int or unsigned int and then excluding anything found that include an = indicating something that is being initialized seems like it should do the job.

grep -E '^int|^unsigned int' myfile.txt | grep -Ev '='
3
  • Or egrep '^(unsigned )?int' to avoid typing both out.
    – thrig
    Sep 12, 2016 at 23:18
  • 2
    (1) This command line is malformed, because the first egrep has an unspecified input, and the second one will read from the file and not the pipe. (2) But, even if we fix that, this rejects declarations that have a comment when there’s an = in the comment. Sep 13, 2016 at 6:34
  • Well, I have corrected my answer per your objections. It does address the OP's original examples, so I won't remove it for its "lacking correctness".
    – MikeA
    Sep 15, 2016 at 22:57

You must log in to answer this question.

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