How to select and read #define lines from a code file

Hi,

I would like to read a .m file
and select the lines which begins with '#define PL-KEY', like

{quote}
#define PL-KEYTAG TAG_values
#define PL-KEYGROUP GROUP_value
#define PL-KEYINFO "INFO_ValueTxtMax120Char" // could be max 120 char
..... more PL-KEY keys
{quote}

and put the rest of that line until a '//' or '/*' , like

{quote}
TAG TAG_values
GROUP GROUP_value
INFO "INFO_ValueTxtMax120Char"
{quote}

into something like a list where my code above will loop through.

I thought using something like


cat "path/to/code.h" | while read line
do
#... what do I have to with "$line" ...
if [[ "$line" == #define PL-KEY* ]] ; then
# yes then... then what????
done


any suggestions?? I noticed today, I am still no shell expert 😟

Thanks again

Posted on Feb 8, 2010 5:53 AM

Reply
24 replies

Feb 12, 2010 10:14 AM in response to BobHarris

With your last submission, it works fine!

But without the extra filter to get the space out, there is that problem.

The comment cut off line leave a space when there is comment ( // or /* )

With my test code ( see further below ), you will see that the comment out line isn't working the way it should.

The first * in
+line="${line%*([[:space:]])/[/*]*}"+
means if I understands zero or more of the matching pattern.

I did expect the same as you, it should remove all the spaces in front of the comment together with the comment.

It leaves ( creates?!) one space when there was a comment, no matter if there where many spaces or tabs in front of the comment.
A second weird thing for me is that when using /* is shows al the folders from root.
So some where it is transformed. I believe this is only because of echo and the real line string contains the /*, because it remove the 'comments' correctly, even echo show my folders.



To show you how I get to this idea, I got this in my .h file.


#import <Cocoa/Cocoa.h>
#import <Example/Example.h>
#define kPL_KEYTAG 'TAG_value' // comment about KeyTag
#define kPL_KEYGROUP "GROUPvalue" /* tekst */
#define kPL_KEYVERSION "2010 feb 10 V1.2 " /* tekst */
#define kPL_KEYINFO 'INFO_Value Txt Max 120 Char width'
#define kPL_KEYNAME ExamplePluginName // bnb
#define kPL_KEYORDER 14// dfd
#define kPL_KEYDESC "Example Plugins"


My Test code with your lines for testing, I did leave the 'if' line out.


shopt -s extglob # enable extended globs +(...), *(...), etc...
cat ${sourceFile} | while read line
do
echo
echo 'before :'${line}--
line="${line%*([[:space:]])/[/*]*}"
echo 'comment out :'${line}--
line="${line##*([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY}"
echo 'Tear off beginning:'${line}--
key=${line%%+([[:space:]])*}
echo 'key :'$key--
value=${line##${key}+([[:space:]])}
echo 'Value :'$value--
done


the result ( see bolded text )

{quote}
*before :#define kPL_KEYTAG 'TAG_value' // comment about KeyTag--*
*comment out :#define kPL_KEYTAG 'TAG_value' --*
*Tear off beginning:TAG 'TAG_value' --*
*key :TAG--*
*Value :'TAG_value' --*

before :#define kPL_KEYGROUP "GROUPvalue" /Applications /Developer /Extra /Groups /Library /Logs.sh /Mac OS X Install Data /Network /Shared Items /System /Users /Volumes /bin /boot /cores /dev /etc /home /mach_kernel /net /pfix.log /private /sbin /sw /tmp /usr /var tekst /--
*comment out :#define kPL_KEYGROUP "GROUPvalue" --*
*Tear off beginning:GROUP "GROUPvalue" --*
*key :GROUP--*
*Value :"GROUPvalue" --*

*before :#define kPL_KEYVERSION "2010 feb 10 V1.2 " /Applications /Developer /Extra /Groups /Library /Logs.sh /Mac OS X Install Data /Network /Shared Items /System /Users /Volumes /bin /boot /cores /dev /etc /home /mach_kernel /net /pfix.log /private /sbin /sw /tmp /usr /var tekst */--*
*comment out :#define kPL_KEYVERSION "2010 feb 10 V1.2 " --*
*Tear off beginning:VERSION "2010 feb 10 V1.2 " --*
*key :VERSION--*
*Value :"2010 feb 10 V1.2 " --*

before :#define kPL_KEYINFO 'INFO_Value Txt Max 120 Char width'--
comment out :#define kPL_KEYINFO 'INFO_Value Txt Max 120 Char width'--
Tear off beginning:INFO 'INFO_Value Txt Max 120 Char width'--
key :INFO--
Value :'INFO_Value Txt Max 120 Char width'--

before :#define kPL_KEYNAME ExamplePluginName // bnb--
comment out :#define kPL_KEYNAME ExamplePluginName --
Tear off beginning:NAME ExamplePluginName --
key :NAME--
Value :ExamplePluginName --

before :#define kPL_KEYORDER 14// dfd--
comment out :#define kPL_KEYORDER 14--
Tear off beginning:ORDER 14--
key :ORDER--
Value :14--

before :#define kPL_KEYDESC "Example Plugins"--
comment out :#define kPL_KEYDESC "Example Plugins"--
Tear off beginning:DESC "Example Plugins"--
key :DESC--
Value :"Example Plugins"--
{quote}

Feb 12, 2010 12:15 PM in response to Obj-D

The first * in
+line="${line%*([[:space:]])/[/*]*}"+
means if I understands zero or more of the matching pattern.

I did expect the same as you, it should remove all the spaces in front of the comment together with the comment.

D'oH! (picture my hand smacking my forehead 🙂 )

The ${var%pattern} chooses the shortest possible match. It does not care that

*([[:space:]])

says zero OR MORE, it finds a minimum of 1 or maybe even zero.

That is to say the % vs %% has a stronger effect on the match selection.

So changing the code so that it first removes the comment, then removing a trailing space is the better approach.

However, again since the % is stingy about how much it deletes, I might change the remove trailing spaces to:

line="${line%%+([[:space:]])}"

Which should remove multiple trailing space (notice the %% being used here) and not remove anything else by mistake.

The ${var%pattern} and friends operators are very useful, but they have their funny little issues that have a way of sneaking up on ya.

Feb 14, 2010 11:48 AM in response to BobHarris

Hi Bob,

Thank you for your wisdom.

I see, like always, read and feel the fine lines interpretation

But I have another one.

Did use your code to do some testings, and from one comes another

Wanted to create a menu where I can choose my test code as a reference

But this line, gives problems
if [[ "$line" = #([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY ]] ; then


I do use it in the following code


#!/bin/bash
# patt-matching.sh
# build menu
line1="1. Read Define Line and split"
line2="2. Replacment inside strings"
#.....
line9="----------------------------"
line99="9. Exit"

# choice 99 keeps the loop running, choose 9 for exit
choice=99
# print menu
echo $line1
echo $line2
#...
echo $line9
echo $line99
echo -n "Please choose a number? "
# Loop while the variable choice is equal 4
# bash while loop
while [ $choice -eq 99 ]; do

# read user input
read choice
# bash nested if/else

if [ $choice -eq 1 ] ; then
# Read Line and split
sourceFile="/Volumes/Repository/_Development/PluginAlpha/PluginMainClass.h"
shopt -s extglob # enable extended globs +(...), *(...), etc...
cat ${sourceFile} | while read line
do
if [[ "$line" = #([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY ]] ; then
#....
fi
done
elif [ $choice -eq 2 ] ; then
#...
elif [ $choice -eq 9 ] ; then

echo "Bye bye!"
exit 0
else
# print menu
choice=99
echo $line1
echo $line2
echo $line9
echo $line99
echo -n "Please choose a number? "
fi
done


Can you explain why? I did try several other things but then the if statement doesn't work well.

this is the error message I see

{quote}
Script-Tests > './pattern and_Stringtests.sh'
1. Read Line and split
2. Replacment inside strings
3. Pattern matching

----------------------------
9. Exit
Please choose a number? ./pattern and_Stringtests.sh: line 45: syntax error in conditional expression: unexpected token `('
./pattern and_Stringtests.sh: line 45: syntax error near `#*(['
./pattern and_Stringtests.sh: line 45: ` if [[ "$line" = # ([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY ]] ; then'

{quote}

Feb 14, 2010 4:35 PM in response to Obj-D

I had to put something between the if and the fi
as well as between the 2 elif statements. You MUST have a
command inside of if statements, or else it will complain. For
the purposes of this example code, I just stuck an echo statement
in the if statements to keep bash happy.

I had to move the *shopt -s extglob* out of the while loop.
Both while loops actually. I stuck it at the beginning of the script,
but anywhere before the first while loop is OK. Why? I don't know.
It just works if I keep it out of the while loop, so I went with it.

Here is the modified code:

#!/bin/bash
# patt-matching.sh
shopt -s extglob # enable extended globs +(...), *(...), etc...
# build menu
line1="1. Read Define Line and split"
line2="2. Replacment inside strings"
#.....
line9="----------------------------"
line99="9. Exit"

# choice 99 keeps the loop running, choose 9 for exit
choice=99
# print menu
echo $line1
echo $line2
#...
echo $line9
echo $line99
echo -n "Please choose a number? "

# Loop while the variable choice is equal 4
# bash while loop
while [ $choice -eq 99 ]; do

# read user input
read choice
# bash nested if/else

if [ $choice -eq 1 ] ; then

# Read Line and split
sourceFile="/Volumes/Repository/_Development/PluginAlpha/PluginMainClass.h"

cat ${sourceFile} | while read line
do

if [[ "$line" = #([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY ]] ; then
echo "#define PL_KEY found"
#....
fi
done

elif [ $choice -eq 2 ] ; then
echo "Choice 2 entered"
#...
elif [ $choice -eq 9 ] ; then

echo "Bye bye!"
exit 0

else
# print menu
choice=99

echo $line1
echo $line2
echo $line9
echo $line99
echo -n "Please choose a number? "

fi
done

Feb 14, 2010 7:06 PM in response to Obj-D


line1="1. Read Define Line and split"
line2="2. Replacment inside strings"
#.....
line9="----------------------------"
line99="9. Exit"

# choice 99 keeps the loop running, choose 9 for exit
# print menu
echo $line1
echo $line2
#...
echo $line9
echo $line99
...
# print menu
choice=99

echo $line1
echo $line2
echo $line9
echo $line99
...

To make your scripting life a little easier, put the menu display in a function

menu()
{
echo "1. Read Define Line and split"
echo "2. Replacment inside strings"
#.....
echo "----------------------------"
echo "9. Exit"
}

Now when you need to display the menu, just code

menu

as the command to display the menu.

And I've combined the prompt into the read command using the -p option, as in:

read -p "Please choose a number? " choice

This is the updated total routine.

#!/bin/bash
# patt-matching.sh
shopt -s extglob # enable extended globs +(...), *(...), etc...
menu()
{
echo "1. Read Define Line and split"
echo "2. Replacment inside strings"
#.....
echo "----------------------------"
echo "9. Exit"
}
# choice 99 keeps the loop running, choose 9 for exit
choice=99
# print menu
menu
# Loop while the variable choice is equal 4
# bash while loop
while [ $choice -eq 99 ]; do

# read user input
read -p "Please choose a number? " choice
# bash nested if/else
if [ $choice -eq 1 ] ; then

# Read Line and split
sourceFile="/Volumes/Repository/_Development/PluginAlpha/PluginMainClass.h"

cat ${sourceFile} | while read line
do
if [[ "$line" = #([[:space:]])define*([[:space:]])*([[:alnum:]])PL_KEY ]] ; then
echo "#define PL_KEY found"
#....
fi
done
elif [ $choice -eq 2 ] ; then
echo "Choice 2 entered"
#...
elif [ $choice -eq 9 ] ; then
echo "Bye bye!"
exit 0
else
# print menu
menu
fi
done

Feb 15, 2010 7:44 AM in response to BobHarris

I am sure that I did press on that link. But I will do it again, because it is very helpful. Thanks again.

It was indeed the shell options line. However, how will people do things when you want half way their code turning globbing en other things off?

set -f and partners or...?


-
In the other elfi statements I do have some code, but it is good pointing on that.


-
About your menu, actually I am go one step further.

I will create some self reading/scanning code what builds the menu.
When script get executed, it will look for itself on disk put it in a catalog and scan every line for an 'if' 'elfi' for '[ $choice -eq 1 ] ; then'.
Then next non empty line for '# title - description of code' part behind that if or elfi line, put that and the choice no. in $menuItemN var what is used to print the menu.

with


# start self scanning code
cat ${0} | while read line
....
# end self scanning code
...
# create menu
...
# the the chosen code between if's
if [ $choice -eq 1 ] ; then
# title - Drink coffee
elfi [ $choice -eq 2 ] ; then
# title - Eat pizza


I hope later today, that I have some time for this.

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

How to select and read #define lines from a code file

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.