2

I've been working on a bash script to search for names of defines, and then grab the hex values for them and put them in the list. Once I have the list of names I'll attempt to search for "#define [name]" using -w to ensure exact match, and then awk '{ print $3 }' to grab the hex value.

However it works if the line in the header file is similar to

a.h:#define [name] 0x0001

But it does NOT work if it is similar to

a.h:    #define [name] 0x0001

How can I get around this? I have tried this

grep -nrw "\s*#define[[:space:]]*$p" . --include=*.h | awk '{ print $3 }'

I thought the \s* would ignore the leading whitespace before #define but it doesn't. Am I doing something wrong?

4
  • 1
    I think you need to use extended grep or the -E flag to use \s
    – ryekayo
    Jul 29, 2015 at 19:45
  • I am, but I believe the issue comes from leading white space causing #define to be shifted from $1 to $2
    – Gammerx
    Jul 29, 2015 at 19:55
  • 1
    You should describe the problem better, it is hard to understand what do you want to achieve.
    – jimmij
    Jul 29, 2015 at 20:05
  • @ryekayo thank you 🙏
    – Leo Bastin
    Nov 4, 2022 at 8:27

2 Answers 2

1

Just use awk (using grep seems redundant to me, since awk already can match a regular expression):

awk '$0~/\s*\#define\s*\[.*\]\s*.*/ {print $3}' *.h

Going through the expression in more detail:

$0 ~ /regexp/          # look for the regular expression in the record
      \s*              # whitespace, any number of times
         \#define      # literal string, '#' has to be scaped
                 \s*   # same as above
                    .* # any character, any number of times, this is
                       # your hex code and you can refine the regex here
{ print $3 }           # print the third field if the record matches

To have this run recursively, e.g.

mkdir -p a/b/c
echo "   #define [name] 0x0001" > a/a.h
echo "   #define [name] 0x0002" > a/b/b.h
echo "   #define [name] 0x0003" > a/b/c/c.h
tree
.
└── a
    ├── a.h
    └── b
        ├── b.h
        └── c
            └── c.h

3 directories, 3 files

since awk needs to be given a list of files to operate on, you could:

find . -type f -name "*.h" \
  -exec awk '$0~/\s*\#define\s*\[.*\]\s*.*/ {print $3}' {} \;
0x0002
0x0003
0x0001
2
  • can this handle recursive as well? (checking *.h from subdirs)
    – Gammerx
    Jul 29, 2015 at 20:16
  • Very well done, this is awesome. Based on some suggestions and testing I have found that grep -Ro '#define\s*\(.*\)' *.h works. -o was tricky to get the entire line but if you just tell it to include anything that comes after, I can now just use awk to get element 3. since grep includes the header file name, if there was a space before #define it would mess it up.
    – Gammerx
    Jul 29, 2015 at 20:44
1

Use grep -o to print only the matching part of the line.

Obviously take the \s part out again, because you don't want that part.

1
  • Problem is that with -o, now I don't get the hex value since it only grabs #define and $p
    – Gammerx
    Jul 29, 2015 at 20:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.