问题
(Couldn't come with any better title)
I'm trying to convert a number of lines, like these:
#define GENERIC_TYPE_METER_PULSE 0x30 /*Pulse Meter*/
#define SPECIFIC_TYPE_NOT_USED 0x00 /*Specific Device Class not used*/
......
#define MFG_ID_WAYNE_DALTON 0x0008 //Wayne Dalton
#define MFG_ID_WILSHINE_HOLDING_CO_LTD 0x012D //Wilshine Holding Co., Ltd
#define MFG_ID_WIDOM 0x0149 //wiDom
......
#define COMMAND_CLASS_ALARM 0x71
#define COMMAND_CLASS_ALARM_V2 0x71
#define COMMAND_CLASS_NOTIFICATION_V3 0x71
#define COMMAND_CLASS_NOTIFICATION_V4 0x71
in a file (c++) to something like these (for Java):
SPECIFIC_TYPE_NOT_USED((byte)0x00) /*Specific Device Class not used*/
MFG_ID_WILSHINE_HOLDING_CO_LTD((byte)0x012D) //Wilshine Holding Co., Ltd
COMMAND_CLASS_ALARM((byte)0x71)
....
I came up with this:
gawk '/^#define/ && / [[:xdigit:]]/ { printf "%s((byte)%s)\n",$2,$3 }'
but there are two issues - it doesn't work with awk
; requires GNU-awk (gawk
) and I also need the end-of-the-line comments in the output whenever available. How can I do that? I'm especially interested using awk
but can live with sed
as well. Cheers!!
回答1:
one sed
solution, i just tested once, so first test some cases
[[bash_prompt$]]$ cat log; echo "########";sed -e 's/#define \([^ ]*\)[ ]*\([^ ]*\)/\1((byte)\2)/g' log
#define GENERIC_TYPE_METER_PULSE 0x30 /*Pulse Meter*/
#define SPECIFIC_TYPE_NOT_USED 0x00 /*Specific Device Class not used*/
#define MFG_ID_WAYNE_DALTON 0x0008 //Wayne Dalton
#define MFG_ID_WILSHINE_HOLDING_CO_LTD 0x012D //Wilshine Holding Co., Ltd
#define MFG_ID_WIDOM 0x0149 //wiDom
#define COMMAND_CLASS_ALARM 0x71
#define COMMAND_CLASS_ALARM_V2 0x71
#define COMMAND_CLASS_NOTIFICATION_V3 0x71
#define COMMAND_CLASS_NOTIFICATION_V4 0x71
########
GENERIC_TYPE_METER_PULSE((byte)0x30) /*Pulse Meter*/
SPECIFIC_TYPE_NOT_USED((byte)0x00) /*Specific Device Class not used*/
MFG_ID_WAYNE_DALTON((byte)0x0008) //Wayne Dalton
MFG_ID_WILSHINE_HOLDING_CO_LTD((byte)0x012D) //Wilshine Holding Co., Ltd
MFG_ID_WIDOM((byte)0x0149) //wiDom
COMMAND_CLASS_ALARM((byte)0x71)
COMMAND_CLASS_ALARM_V2((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V3((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V4((byte)0x71)
[[bash_prompt$]]$
for a proper format, ( in my sense, it is aligning the comment ) , i was not able to come up with any sed
solution, ( i am interested in one ) here is an awk
solution ( looks like a little clumsy, but self explanatory..
[[bash_prompt$]]$ awk '{str=sprintf("%s((byte)%s)", $2, $3);len=length(str); \
> for(i=50;i>len;i--) str=sprintf("%s ", str); print str (NF>3?substr($0,index($0,$4)):"")}' log
GENERIC_TYPE_METER_PULSE((byte)0x30) /*Pulse Meter*/
SPECIFIC_TYPE_NOT_USED((byte)0x00) /*Specific Device Class not used*/
MFG_ID_WAYNE_DALTON((byte)0x0008) //Wayne Dalton
MFG_ID_WILSHINE_HOLDING_CO_LTD((byte)0x012D) //Wilshine Holding Co., Ltd
MFG_ID_WIDOM((byte)0x0149) //wiDom
COMMAND_CLASS_ALARM((byte)0x71)
COMMAND_CLASS_ALARM_V2((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V3((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V4((byte)0x71)
回答2:
You can use this awk one-liner:
awk '$1=="#define" && $3~/[0-9]+$/{printf "%s((byte)%s)", $2, $3; $1=$2=$3=""; print}' file
EDIT: Here is an awk that you can try for better alignment of comments:
awk '$1 == "#define" && $3 ~ /[0-9]+$/{s=sprintf("%s((byte)%s)", $2, $3); $1=$2=$3="";
printf("%-50s\t%s\n", s, $0)}'
OUTPUT:
GENERIC_TYPE_METER_PULSE((byte)0x30) /*Pulse Meter*/
SPECIFIC_TYPE_NOT_USED((byte)0x00) /*Specific Device Class not used*/
MFG_ID_WAYNE_DALTON((byte)0x0008) //Wayne Dalton
MFG_ID_WIDOM((byte)0x0149) //wiDom
COMMAND_CLASS_ALARM((byte)0x71)
COMMAND_CLASS_ALARM_V2((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V3((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V4((byte)0x71)
回答3:
$ cat tst.awk
/^#/ {
hd[++nr] = sprintf("%s((byte)%s)", $2, $3)
lgth = length(hd[nr])
maxLgth = (lgth > maxLgth ? lgth : maxLgth)
sub(/[^/]+/,"")
tl[nr] = $0
}
END {
for (i=1; i<=nr; i++)
printf "%-*s%s\n", maxLgth+2, hd[i], tl[i]
}
$ awk -f tst.awk file
GENERIC_TYPE_METER_PULSE((byte)0x30) /*Pulse Meter*/
SPECIFIC_TYPE_NOT_USED((byte)0x00) /*Specific Device Class not used*/
MFG_ID_WAYNE_DALTON((byte)0x0008) //Wayne Dalton
MFG_ID_WILSHINE_HOLDING_CO_LTD((byte)0x012D) //Wilshine Holding Co., Ltd
MFG_ID_WIDOM((byte)0x0149) //wiDom
COMMAND_CLASS_ALARM((byte)0x71)
COMMAND_CLASS_ALARM_V2((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V3((byte)0x71)
COMMAND_CLASS_NOTIFICATION_V4((byte)0x71)
Change the 2
in maxLgth+2
to whatever spacing you want between the longest value and it's associated comment.
来源:https://stackoverflow.com/questions/19587314/string-pattaren-matching-using-awk