Awk string extraction not working with variable [duplicate] - bash

This question already has answers here:
How do I use shell variables in an awk script?
(7 answers)
Closed 7 years ago.
echo boy:foo:cheese | awk -F":" '{print $1}'
Result: boy
echo boy:foo:cheese | awk -F":" '{print $2}'
Result: foo
i=1
echo boy:foo:cheese | awk -F":" '{print $($i)}'
Result: boy:foo:cheese
Also,
i=1
echo boy:foo:cheese | awk -F":" '{print $i}'
Result: boy:foo:cheese
I want to be able to print the ith item. The only possible reason this happens is that awk doesn't support variables for its print values? My end goal here is to loop through the string and get:
boy
foo
cheese

Figured it out!
echo "cat:test:cheese" | awk -F":" '{print $'$i'}'
cat

You appear to have noticed that shell variables and awk positional/field variables share a syntax $# but failed to consider that that means awk can't expand both of them.
Either the shell expands the variable or the shell does, not both.
The single quotes around the awk script mean the shell doesn't so awk does. So '{print $2}' tells awk to print the second field. Similarly for $1 telling awk to print the first field. Whereas, '{print $($i)}' tells use the awk variable i and then use that value as a positional/field variable ($<i>) and then use that as yet another positional/field variable $(<$<i>>).
Variables in awk default to 0 when uninitialized so that sequence is:
$($i)
$($0)
$(input line)
``
which then causes awk to dutifully print nothing.
The correct way to use a shell variable is to pass it to awk using -v var="$1" and then using var in awk. Non-positional/non-field variables in awk do not use the $ sigil.

Related

Match a length of string in column using awk

I'm trying to extract the column which matches the date pattern like: YYYY-MM-DD, but didn't understand the difference between below commands
Working command
echo 1,2,3,4,2015-12-34 | awk -F, '{if($5~/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/) print $1}'
Not working command
echo 1,2,3,4,2015-12-34 | awk -F, '{if($5~/^[0-9]{d}-[0-9]{2}-[0-9]{2}$/)print $1}'
Can someone explain me why it's happening, am i missing a granular thing?
You could try following and let me know if this helps you.
echo 1,2,3,4,2015-12-34 | awk --re-interval -F, '{if($5~/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/)print $1}'
OR
echo 1,2,3,4,2015-12-34 | awk --re-interval -F, 'match($NF,/[0-9]{4}-[0-9]{2}-[0-9]{2}/){print $1}'
NOTE: My awk version is OLD so I am using --re-interval you could remove it in case you have recent awk version.

Shell Scripting: Echo vs save to variable

Why do these do different things?
ENTRY="banana#Apple"
HOST_ID=$ENTRY | awk -F '#' '{print $2}'
echo $HOST_ID
echo $ENTRY | awk -F '#' '{print $2}'
In the echo command, the data is displayed as expected. In the save to variable command, the data is not, and the variable is left empty.
This:
HOST_ID=$ENTRY | awk -F '#' '{print $2}'
means this:
HOST_ID='banana#Apple' | awk -F '#' '{print $2}'
In other words, you're running two commands in separate subshells — HOST_ID='banana#Apple', and awk -F '#' '{print $2}' — and piping the output of one to the other. This doesn't accomplish anything: HOST_ID='banana#Apple' produces no output, so the awk command gets no input, so it doesn't print anything. (And because of the subshells, even the HOST_ID='banana#Apple' part has no effect: it's setting that variable in a subshell, rather than in the parent shell that's running the overall command. So the value disappears almost immediately)
Instead, you want to write:
HOST_ID="$(echo "$ENTRY" | awk -F '#' '{print $2}')
or:
HOST_ID="$(awk -F '#' '{print $2}' <<< "$ENTRY")
or perhaps (if you're only ever expecting $ENTRY to have two fields):
HOST_ID="${ENTRY#*#}"

How to write a bash and define awk constants in command line [duplicate]

This question already has answers here:
Using awk with variables
(3 answers)
Closed 8 years ago.
As a part of my bash, I want to pass some constant from command line to awk. For example, I want to subtract constant1 from column 1 and constant2 from column 5
$ sh bash.sh infile 0.54 0.32
#!/bin/bash
#infile = $1
#constant1 = $2
#constant2 = $3
cat $1 | awk '{print $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6}'
thank you very much for your help
As awk is it's own language, by default it does not share the same variables as Bash. To use Bash variables in an awk command, you should pass the variables to awk using the -v option.
#!/bin/bash
awk -v constant1=$2 -v constant2=$3 '{print($1-constant1),($5-constant2)}' $1
You'll notice I removed cat as there is no need to pipe cat into awk since awk can read from files.
you need to remove gaps when defining vaariables:
#!/bin/bash
infile=$1
constant1=$2
constant2=$3
cat $1 | awk '{print $1 $2 $3 $4 $5 $6}'

How to pass a bash variable as value of awk parameter?

I would like to replace a variable inside the the awk command with a bash variable.
For example:
var="one two three"
echo $var | awk "{print $2}"
I want to replace the $2 with the var variable. I have tried awk -v as well as something like awk "{ print ${$wordnum} } to no avail.
Sightly different approach:
$ echo $var
one two three
$ field=3
$ echo $var | awk -v f="$field" '{print $f}'
three
$ field=2
$ echo $var | awk -v f="$field" '{print $f}'
two
You've almost got it...
$ myfield='$3'
$ echo $var | awk "{print $myfield}"
three
The hard quotes on the first line prevent interpretation of $3 by the shell. The soft quotes on the second line allow variable replacement.
You can concatenate parts of awk statements with variables. Maybe this is what you want in your script file:
echo $1|awk '{print($'$2');}'
Here the parts {print($ and the value of local variable $2 and );} are concatenated and given to awk.
EDIT: After some advice rather don't use this. Maybe as a one-time solution. It's better to get accustomed to doing it right right away - see link in first comment.

Use bash variable in AWK expression

I tried the following snippet in a shell script but awk didn't find $REF
REF=SEARCH_TEXT
echo "some text" | awk '/$REF/{print $2}'
Instead of quoting games in the shell, use the -v option to pass the shell variable as an awk variable:
awk -v ref="$REF" 'match($0, ref) {print $2}'
If $REF is just text and not a regular expression, use the index() function instead of match().
You question is worded really poor...
Anyway, I think you want this:
REF=SEARCH_TEXT
echo "some text" | awk "/$REF/{print \$2}"
Note the escaping of $2 and the double quotes.
or this:
REF=SEARCH_TEXT
echo "some text" | awk "/$REF/"'{print $2}'
Note the judicious use of double and single quotes and no escaping on $2.
You have to use shell expansion, as otherwise it would encompass exporting a shell variable and using it from the environment with awk - which is overkill in this situation:
export REF=SEARCH_TEXT
echo "some text" | awk '{if (match($0, ENVIRON["REF"])) print $2}'
I think awk does not support variables in /.../ guards. Please correct me if I'm wrong.
In gawk, you have the ENVIRON array, e.g. awk 'END{print ENVIRON["REF"]}' /dev/null will print your variable if you've exported it out from the shell to sub-processes.

Resources