1

I am trying to count the null records of a column in a file, subject to a condition. But the condition is not working.

  • Example input: fixed width file,
                 761128424607/22/20197611284246CAD052020DHH 0073578EKLAVY3
ELEKBAFXXL7900271761128424406/22/20197611284244CAD042020DKA 0038244EDITTU8                     
                 761128424606/22/20197611284246CAD052020DHH 0073578EKLAVY3                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
ELEKBAFXXL7900271761128424406/22/20197611284244CAD042020DKA 0038244EDITTU8
  • code
    RE='[[:space:]]{17}' awk -v m=1 -v p=17 -v r='&& substr($0,28,2)==06'
        $'BEGIN{re = ENVIRON["RE"]}{c = substr($0,m,p)}  c ~ "^(" re ")$" r  {N++}  END {print N+0}' <  input_file.txt
    
  • Desired output: 1, since 2 records having null in file and out of this 1 record satisfies condition substr($0,28,2)==06
  • Actual output: 0, which is wrong
5
  • @rowboat its zero sorry . i am editing the question. Basically i am looking for a flexibility to pass conditions to awk statement. is there a way to do this. This issue occurs only for fixed width. for the delimited records i have got correct. I am pasting the same logic for delimited version. Commented Aug 6, 2021 at 15:29
  • delimited file logic for finding nulls count subject to a logic: - thres=$( RE="$col_null_patt" awk -F "$sep" -v n="$col_pos" -v r="$col_cond" 'BEGIN {m = ENVIRON["RE"]} NR>1 && $n ~ "^" m "$" r {N++} END{print N+0}' "$cp_input") Commented Aug 6, 2021 at 15:33
  • 1
    @rowboat GNU Awk 4.0.2 Copyright (C) 1989, 1991-2012 Free Software Foundation. Commented Aug 6, 2021 at 15:36
  • 3
    Do the massive chains of blanks at the end of your sample input really exist in your data? Is it important for them to exist in the example in your question? If the answer to either question is "no" then please edit your question to remove them.
    – Ed Morton
    Commented Aug 6, 2021 at 16:07
  • It looks like you're trying to construct an awk script from the values of some shell variables. In that case, construct the entire script as a shell variable and then run it. e.g. awkscript="......"; awk "$awkscript". BTW, programs that generate code which is later executed are not unusual, but they do require even more care and attention to detail than usual.
    – cas
    Commented Aug 7, 2021 at 4:44

4 Answers 4

3

This would do what you're asking for by letting the contents of the shell variable r expand to become part of the awk script before awk gets called to interpret it but there's almost certainly a better way to do whatever it is you're really trying to do:

$ r='&& substr($0,28,2)=="06"'
$ RE='[[:space:]]{17}' awk -v m=1 -v p=17 '
    BEGIN { re = ENVIRON["RE"] }
    { c = substr($0,m,p) } 
    c ~ "^(" re ")$" '"$r"' { N++ }
    END { print N+0 }
' file
1

If you have to write && substr($0,28,2)=="06" somewhere though, then it's not at all obvious why you wouldn't just write it in the awk script instead of in a shell variable - whatever you're trying to do, there's got to be a better way.

0
2
awk ... r='&& substr($0,28,2)==06'
    '... c ~ "^(" re ")$" r  { ... } '

This looks like you're trying to use an awk variable to build the condition on the fly? That is, to use the contents of the awk variable r as part of awk syntax.

I don't think that can work. In awk, back to back values are taken as string concatenation, so that turns into something like c ~ "^(" re ")$&& substr($0,28,2)==06", i.e. it would take the contents of r as part of the regex to match against.

E.g. awk -v var=bar '$0 ~ "foo" var' would print lines containing foobar, and it works similarly even if the variable contains && or such.

It probably won't work anywhere near that in any other programming language either, since separation between code and data is pretty much a requirement for sane and safe programs. It doesn't work like that even in the shell. (Without eval or such.)

Just write the whole expression out in full.

2

With some changes you can get it to output expected results:

RE='[^[:space:]]' awk -v m=1 -v p=17 \
$'(r=substr($0,28,2)=="06")&&
(substr($0,m,p) !~ re) {N++}
BEGIN {re = ENVIRON["RE"]}
END {print N+0}' < input_file.txt

Edits:-

  • Convert the awk variable r declared on the commandline to be inside the $'...' code block.
  • Remove the &&, turning it to a boolean.
  • stick the && between the c ~ ... and r boolean conditions.
  • Change the numeric comparison ==06 to a string comparison =="06"
1

With GNU awk, you can use the FIELDWIDTHS variable to specify the widths of fixed width fields:

gawk '($1!~/[^ ]/) && ($3=="06"){++c} END{print c+0}' FIELDWIDTHS='17 10 2 *' file

You could try to parameterise the awk script – some attempts at that:

str=06 gawk -v FIELDWIDTHS='17 10 2 *' '
  ($1 !~ /[^ ]/) && ($3"" == ENVIRON["str"]) {
      ++c
  }
  END {print c+0}
' file
str=06 rexp='^ {17}$' gawk -v FIELDWIDTHS='17 10 2 *' -v rexp_col=1 -v str_col=3 '
  ($rexp_col ~ ENVIRON["rexp"]) && ($str_col"" == ENVIRON["str"]) {
      ++c
  }
  END {print c+0}
' file

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .