I new to awk and playing around with it. When trying to use the ternary operator, at some point I wanted to execute two operations upon true condition, and as I couldn't find the syntax to do so I tried to smuggle one of the two operations inside the condition to take advantage of the lazy evaluation.
I have an input file as follow:
file.csv
A,B,C,D
1,,,
2,,,
3,,,
4,,,
5,,,
6,,,
7,,,
8,,,
And I'd like, for the sake of the exercise, to put assign B and C to 0 if A is less than 5 ; C to 1 if A is 5 or more. I guess the ternary operator is a terrible way to do this but this is not my point.
The question is: why does the following line outputs that? How does awk parse this expression ?
awk '(FNR!=1){$1<5 && $3=0 ? $2=0 : $2=1}{print $0}' FS=, OFS=, file.csv
Output:
1,1,1,
2,1,1,
3,1,1,
4,1,1,
5,,,
6,,,
7,,,
8,,,
I was expecting the $3=0
expression to be executed and evaluated to true
, and being skipped when the first part of the condition ($1<5
) is false.
Expected result:
1,0,0,
2,0,0,
3,0,0,
4,0,0,
5,1,,
6,1,,
7,1,,
8,1,,
Extra question: can I actually use the ternary operator and have in it several instructions executed depending on the condition value ? Is it only a bad practice or actually impossible ?
1st solution: You should have like this code, written and tested with your shown samples and attempts. I have used ternary operators to check if value of 1st field is lesser than 5 or not and based on that setting values for 2nd and 3rd fields here.
awk '
BEGIN { FS=OFS="," }
FNR==1{
print
next
}
{
$2=($1<5?0:$1)
$3=($1<5?0:$3)
}
1
' Input_file
2nd solution(Generic approach): If you have to pass N number of fields to be checked in program then better create a function and do the checks and assignment there, using again ternary operators here for computation.
Where:
threshold
is an awk
variable which is assigned to 5
value by which you want to do comparison fir 1st field.fieldCompare
is again an awk
variable which contains 1
in this case since we want to compare 1st field value to 5 here.checkValue
is function where field numbers(eg: 2
and 3
in this case) are being passed with comma separated values to be checked in a single shot within function.awk -v threshold="5" -v fieldCompare="1" '
function checkValue(fields){
num=split(fields,arr,",")
for(i=1;i<=num;i++){
fieldNum = arr[i]
$fieldNum = ($fieldCompare<threshold?0:$fieldNum)
}
}
BEGIN { FS=OFS="," }
FNR==1{
print
next
}
checkValue("2,3")
1
' Input_file
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With