views:

271

answers:

2

Hi

I am trying to output 'awk' result to file in my script, with no success. Using '>' does not work, why?

for a in $(find $OUPUT_DIR/ -maxdepth 1 -mindepth 1 -type d -printf "%P\n")
do
    echo $a is a directory
    awk -F, '{ if ($10 == '"$a"') print $0 }' $OUPUT_DIR/CDRNOutput_${CDR_DATE}.csv > $OUPUT_DIR/$a/CDR-${CDR_DATE}.csv
done 
+3  A: 

Output redirection is generally a feature of the shell you're working with and, given how much use it gets, I'd be pretty amazed if you'd found a bug in it :-)

Are you sure you're not trying to do redirection with awk itself rather than the shell?

What happens when you do:

echo 'hello' | awk '{print}' >qq.tmp

Update:

If this is your code as stated, it's because the $a is not being expanded by your shell script since the awk command is within single quotes.

for a in $(find $OUPUT_DIR/ -maxdepth 1 -mindepth 1 -type d -printf "%P\n")
do
    echo $a is a directory
    awk -F, '{ if ($10 == '"$a"') print $0 }' $OUPUT_DIR/CDRNOutput_${CDR_DATE}.csv > $OUPUT_DIR/$a/CDR-${CDR_DATE}.csv
done

What I tend to do is pass in specific values to awk using the -v option, something like (in your case):

awk -F, -v a=$a '{ if ($10==a) print $0 }' ...

Then the variables become first-class awk citizens without having to worry about who's doing the expansion.


Further update:

I'm standing behind my original advice. There's something definitely screwy with the method chosen.

I have a directory in my home directory called XpVm (among others) and I've created the file CDRNOutput_X.csv containing the single line:

1,2,3,4,5,6,7,8,9,XpVm,11

When I execute:

for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, '{
        if ($10 == '"$a"') {
            print $0
        } else {
            print "NO";
        }
    }' ./CDRNOutput_X.csv
done

(I've stripped out directories starting with . since they were causing another problem), I get this output:

workspace is a directory
NO
Documents is a directory
NO
XpVm is a directory
NO
Downloads is a directory
NO

which is clearly not what is expected. However, when I use the -v option to awk as I originally suggested, the command:

for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, -v a=$a '{
        if ($10 == a) {
            print $0
        } else {
            print "NO"
        }
    }' ./CDRNOutput_X.csv
done

(the only difference being the changes to a), I get:

workspace is a directory
NO
Documents is a directory
NO
XpVm is a directory
1,2,3,4,5,6,7,8,9,XpVm,11
Downloads is a directory
NO

which is correct.


Final update (hopefully):

I think I have the problem solved. I'm on a different machine now (so the directory names are simply tmp and tmp2) and, when I run the original script:

for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, '{
        if ($10 == '"$a"') {
            print $0
        } else {
            print "NO";
        }
    }' ./CDRNOutput_X.csv
done

with a modified CDRNOutput_X.csv containing tmp instead of XpVm, I get:

tmp is a directory
NO
tmp2 is a directory
NO

That's because the if statement is being seen by awk as:

        if ($10 == tmp) {

(without quotes, since the quotes are actually outside the awk string being used to surround the directory name). This will test $10 for equality against the awk variable called tmp rather than the actual string "tmp". What you need is to make sure that the quotes are inside the awk script, like:

        if ($10 == "tmp") {

and you can do this with the following script (only the if line has changed):

#!/bin/bash
for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, '{
        if ($10 == "'"$a"'") {
            print $0
        } else {
            print "NO";
        }
    }' ./CDRNOutput_X.csv
done

Note that the double quotes are duplicated. I've still kept the double quotes immediately around $a in case someone's committed the heinous crime of creating a file with a space in it :-)

Running that script produces:

tmp is a directory
1,2,3,4,5,6,7,8,9,tmp,11
tmp2 is a directory
NO

which is what I think you were aiming for.

So, the upshot is, if you don't want to use awk variables, you can just change your awk string from:

'{ if ($10 == '"$a"') print $0 }'

to:

'{ if ($10 == "'"$a"'") print $0 }'

and it should function okay.

paxdiablo
@paxdiablo - that statement is ending the single quote and then surrounding $a with double-quotes so it will work. Change awk to echo and give it a try to confirm for yourself.
R Samuel Klatchko
Actually, awk also has a redirection mechanism:awk '{print > "filename"}'writes to a file called filename.
Jouni K. Seppänen
tried this command:awk -F, -v a=$a '{ if ($10 == a) print $0 }' $OUPUT_DIR/CDRNOutput_${CDR_DATE}.csv > $OUPUT_DIR/$a/CDR-${CDR_DATE}.csvstill don't work
Erik Sapir
@Jouni, that particular variant will overwrite the file each time which is unlikely to be what's desired. @RSam, good point (though I still prefer mine). But now the test works, we need more info from OP.
paxdiablo
I am using -v (as mentioned in previous comment) but still don't work.I used 'sex -X' so i could see the command, and the command is:awk -F, -v a=512543 '{ if ($10 == a) print $0 }' /tmp/Camps/CDRNOutput_2010-01-01.csv
Erik Sapir
No, awk's redirection does not overwrite the file each time the print statement is called. It does the same thing as redirection in the shell, except in awk you can redirect to different files in different branches of your code.
Jouni K. Seppänen
@Jouni, I stand corrected, my misunderstanding.
paxdiablo
The '...'"$a"'...' quoting means that the bare, unquoted value of $a will be part of the awk program: to the shell this is a concatenation of three quoted strings, the middle one double-quoted and the others single-quoted. The solution is to add some extra quotation marks, or to use -v as suggested in paxdiablo's answer.
Jouni K. Seppänen
A: 

since you have find command with -mindepth and maxdepth set to 1, you can just do it with the shell

#!/bin/bash
CDR_DATE="somedate"
infile=CDRNOutput_${CDR_DATE}.csv
outfile=CDR-${CDR_DATE}.csv
OUPUT_DIR="/some/dir"
cd $OUPUT_DIR
for dir in */
do
    echo "${dir%/*} is a directory"
    dir=${dir%/*}
    while read -r a b c d e f g h i j k
    do
        case "$j" in
            $dir) echo $a $b $c $d $e $f $g $h $i $j $k >> $dir/$outfile;;
        esac
    done < $infile
done
ghostdog74