Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I've been trying to hack a little code extraction script together, but I can't get it to work.

My goal is to examine all .txt files in a directory. If it contains a line which doesn't start with a tab and includes cat.*.c, then extract lines from there (exclusive) to the last line which starts with } (inclusive) and save it to a file with the same names as the source except for with a .c extension.

My first stab at trying to find it was this:

find . -name "*.txt" -print0 | xargs -0 awk '/[^ \t]cat .*.c/,/[^ \t]}/'

I'm not sure why, but the tab matching doesn't work.

Obviously I would need to do a bit more. I'll need to loop through the files from find and grab the file directory & name...

filename=$(basename "$1")
filename="${filename%.*}"
dirname=`dirname "$1"

Firstly, though, I need to figure out how to get the text I want. Is awk an appropriate tool for the job? Would sed/grep be a better choice?

Any help is greatly appreciated! Thank you!

P.S. I've tried searching around, but the tab issue seems to be unique to me. And lopsided matching (ex/inclusive) seems to be infrequently used also...

share|improve this question
    
Note that your awk patterns require some text (which isn't whitespace) before the cat and the }. Is that intended? If not, you could try using /(^|[^ \t])cat .*\.c/,/(^|[^ \t])\}/ instead. (The \} just to be explicit that this isn't an unmatched regex brace. Bare } also does work there.) –  dubiousjim Oct 19 '12 at 15:58
    
About which tool to use: for multiline pattern matching, you do want to use awk or sed. The filename/directory parsing you mention wanting to do make awk sound like the best choice. You could handle that inside an awk action-block that's more complex than the (implicit) { print $0 } block you're using here. –  dubiousjim Oct 19 '12 at 16:03
    
are you running linux and do you have pcregrep available? –  1_CR Oct 19 '12 at 16:31
add comment

2 Answers

up vote 0 down vote accepted

If I understand correctly, you want something like:

awk '
  NR==1, !/^[ \t]/ && /cat.*\.c/ {next}
  {a = a $0 "\n"}
  /^\}/ {printf "%s", a; a=""}'

And to integrate with find:

find . -name '*.txt' -type f -exec awk '
  FNR == 1 {
    if (newfile != "") close(newfile)
    newfile = FILENAME
    sub(/\.txt$/, ".c", newfile)
    a = ""
  }
  FNR==1, !/^[ \t]/ && /cat.*\.c/ {next}
  {a = a $0 "\n"}
  /^\}/ {printf "%s", a > newfile; a = ""}' {} +
share|improve this answer
    
If the input contains any blocks terminated by "}" but not starting with a matching "...cat" line (and after a genuine "...cat...}" block), this script will wrongly print them out. Whether it's worthwhile to complicate the script to accommodate that, or just leave it be, I guess depends on what the input is like. –  dubiousjim Oct 19 '12 at 17:38
    
@dubiousjim, that's what I understood the requirement to be ("up to the last line starting with }"). Otherwise, the script would be a lot simpler and would need to store lines. –  Stephane Chazelas Oct 19 '12 at 17:48
    
Ah yes, you are correct. –  dubiousjim Oct 19 '12 at 18:06
    
Thanks for the assistance. It works perfectly. –  user1759695 Oct 22 '12 at 22:58
add comment

Finally had some time to play with sch's answer. Here's my "final" script, just in case someone else finds it useful:

for i in `find . -name '*.txt' -type f`
do
    awk '
FNR == 1 {
    if (newfile != "") close(newfile)
    newfile = FILENAME
    sub(/\.txt$/, ".c", newfile)
    a = ""
}
FNR==1, !/^[ \t]/ && /cat.*\.c/ {next}
{a = a $0 "\n"}
/^\}/ {printf "%s", a > newfile; a = ""}' $i

    filename=$(basename "$i")
    filename="${filename%.*}"
    dirname=`dirname "$i"`
    cfilename="${dirname}/${filename}.c"
    if [ -f ${cfilename} ]
    then
        echo "Extracted code from: ${dirname}/${filename}.txt"
        gccErrors=`gcc -Wall ${cfilename} -o "${dirname}/${filename}" -lm 2>&1`
        if [ -n "${gccErrors}" ]
        then
            echo ${gccErrors}
            gccErrorFile="${dirname}/${filename}_GCCERRORS.txt"
            if [ -f ${gccErrorFile} ]
            then
                echo "Can't write to \"${gccErrorFile}\" File already exists!"
            else
                echo ${gccErrors} > ${gccErrorFile}
            fi
        fi
    fi
done
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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