Awk parameter substitution not working

I am trying to pass parameter to the awk command but not getting substituted. Can you please help? I can see the value of $i inside awk is not representing the parameter but uses the file record.

grep NVARCHAR2 test2 | awk '{print substr($4,12)}' > Nvarcharfields
for i in `cat Nvarcharfields`
do
echo $i
awk '{if (substr($2,13)=="\"$i\"")  {$10="ChangeX"} print $0}' test2 > test6
done

Your immediate problem is that the whole awk command is single-quoted, so the shell does nothing more to it.

The doubled double-quotes just define an empty string, and have no purpose.

$i refers to field i in the current line. As i is undefined, awk treats it as 0, and $0 is indeed the whole input line.

If you have GNU/awk, you should inject any shell variable as a named argument:

awk -v Item="${i}" '{ if (substr($2, 13) == Item) $10="ChangeX"; print $0}'

You iterate over file test2 for every grepped value. Did you consider what happens with duplicates? Cutting off the first 11 characters of a field (even a unique one) can create duplicates.

Any combination of grep, awk, iteration, awk can usually be made into a single awk with the use of arrays. I am particularly suspicious of for i in cat.

It would be helpful to see some data samples. I suspect between substr (12) and substr (13) may lurk a one-off error.

2 Likes

Thanks for your response. This command is working fine when I run through command line but in script the value is not getting substituted. Through debug (sh -x), I can see the below command is running:
awk -v 'Item="ZWL2N1"' '{ if (substr($2,14,6) == Item) $3="ChangeX"; print $0}' test2
The single quote in 'item="ZWL2N1"' is making the issue seems.

What @Paul_Pedant has posted and what you put in the script isn't the same.
You have an extra single quote preseeding Item

1 Like

Perhaps the extra ' ' are generated by the debug output? (Especially if sh is not linked to bash.)

1 Like

Yes. The debug script is producing this extra quote.

@Vinod2 Could post the entire script then?
And the output.

grep NVARCHAR2 test2 | awk '{print substr($4,12)}' > Nvarcharfields

for i in cat Nvarcharfields
do
echo $i

awk -v Item=${i} '{ if (substr($2,14,6) == Item) $3="ChangeX"; print $0}' test2 > test6

cp test6 test2

done

this line

for i in cat Nvarcharfields
i will be set first to cat then Nvarcharfields
do you mean
for i in "$(cat Nvarcharfields)"
or something else ?

copy/paste a couple of lines of the Nvarcharfields file

Nvarchar file data looks below:
"ZXXXX1"
"ZXXXX2"
"ZXXXX3"
"ZXXXX4"
"ZXXXX5"

for i in "backtik" cat Nvarcharfields "backtik"

In this forum backticks mean a low level protection, and are not shown then.
Please wrap your whole code in ``` (markdown) lines; this means a strong protection of the code lines, and single backticks in it are just backticks. (And the tripple backticks markdowns are not shown then.)

BTW backticks in the shell are deprecated, use the POSIX $( ) instead!

for i in $(cat Nvarcharfields)
1 Like

If you single-quote the expression after -v, two separate bad things happen:

(a) The single quotes protect the double-quotes, which then become part of the value of the variable itself, so it then cannot match the data as expected.

$ echo | awk -v 'Item="ZWL2N1"' '{ print Item }'
"ZWL2N1"

(b) The single quotes prevent the expansion of the variable as well.

$ i=ZWL2N1
$ echo "${i}"
ZWL2N1
$ echo | awk -v 'Item="${i}"' '{ print Item }'
"${i}"

If you write the code as I specified, no bad things happen.

$ echo | awk -v Item="ZWL2N1" '{ print Item }'
ZWL2N1
$ echo | awk -v Item="${i}" '{ print Item }'
ZWL2N1
1 Like

Command line is working fine. But used in script then we can see the single quote in the debug script.

I do not get that result:

$  cat ./fooawk
#! /bin/bash
set -x
i="ZWL2N1"
echo | awk -v Item="${i}" '{ print Item }'
$  ./fooawk
+ i=ZWL2N1
+ echo
+ awk -v Item=ZWL2N1 '{ print Item }'
ZWL2N1
$  

Conclusion:
(a) Your command in the script is different to the one on the command line.
(b) You are not running the script that you think you are.
(c) You are running a shell that implements set -x badly, by quoting things that are not really there.

Maybe your value being passed with the -v has whitespace or special characters. In that case, Bash single-quotes the whole arg to -v to avoid word-splitting. Because the quotes are removed when the command is parsed, the value passed with -v is a single arg by the time awk sees it.

$  cat ./fooawk
#! /bin/bash
set -x
i="ZWL 2N1"
echo | awk -v Item="${i}" '{ print Item }'
$  ./fooawk
+ i='ZWL 2N1'
+ echo
+ awk -v 'Item=ZWL 2N1' '{ print Item }'
ZWL 2N1

Please show exactly and completely what you script does do. Being told "it still has quotes" is unhelpful if you don't understand why they might be necessary in some cases.

This is one looong running thread with confusing posts from the OP.
your original script:

grep NVARCHAR2 test2 | awk '{print substr($4,12)}' > Nvarcharfields
for i in `cat Nvarcharfields`
do
echo $i
awk '{if (substr($2,13)=="\"$i\"")  {$10="ChangeX"} print $0}' test2 > test6
done

How about this withOUT the loop and all the extra hops you wanted to go with:

#/bin/bash
awk '
FNR==NR {if (/NVARCHAR2/) f1[substr($4,12)];next}
substr($2,13) in f1 {$10="ChangedX"}
1
' test2 test2 > test6

Not tested. Just simplifying the steps, and I don't know WHAT is behind these steps/logic and/or what's the bigger picture you're trying to achieve, but it should get you started with the better skeleton.
It could also help YOU/us, if you could provide a small representative sample of test2.
BTW, PLEASE start using markdown code tags when posting code/data samples - I believe you've been asked/warned before.

1 Like