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

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}'

Related

Bash unable to assign value [duplicate]

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 1 year ago.
Got a bit of a problem. I'm new to bash and I'm trying my hardest, but I can't figure out how to assign the desired output to the variable. Running this command in the prompt
wc -l data.txt | awk '{ print $1 }'
yields the result 12, which is desired. However if I put it in the test.sh file, it won't work. I've tried different quotations, but all I've managed to get is the entire line as a string...
Test.sh
#! /bin/bash
# Count lines for data.txt files
data1=wc -l data.txt | awk '{ print $1 }'
echo "Lines in data.txt: $data1"
exit
I think you want:
data1="$(wc -l data.txt | awk '{ print $1 }')"
The $() syntax causes bash to execute that expression and replace it with the results.
Actually, powershell does allow you to do a straight = assignment like you did...

non-printable character not recognised as field separator

I have a file. Its field separator is non-printable character \x1c (chr(28) in Python). In VI it looks like a^\b^\c but using cat I just see abc. The fieldseparator ^\ is not seen.
I have a simple awk command:
awk -F $ā€™\x1cā€™ ā€˜{print NF}ā€™ a
to get the total number of fields. It works on MacOS, but on AIX, it fails. It seems AIX can't recognize the field separator. So the output is 1 meaning the whole line is considered one field.
How to do this on AIX? Any idea is much appreciated.
I was able to reproduce this on SOLARIS running ksh.
sol bash $ printf '\034a\034b\034c' | cat -v
^\a^\b^\c$
sol bash $ printf '\034a\034b\034c' | awk -F$'\x1c' '{print NF}'
4
sol bash $ printf '\034a\034b\034c' | awk -F$'\034' '{print NF}'
4
sol ksh $ printf '\034a\034b\034c' | cat -v
^\a^\b^\c$
sol ksh $ printf '\034a\034b\034c' | awk -F$'\x1c' '{print NF}'
1
sol ksh $ printf '\034a\034b\034c' | awk -F$'\034' '{print NF}'
1
I cannot confirm if this is a ksh issue or awk issue, as other cases fail on both.
sol ksh/bash $ printf '\034a\034b\034c' | awk 'BEGIN{FS="\034"}{print NF}'
1
All the above cases work successfully on any Linux system (which run by default GNU awk), but it seemed to have failed gloriously.
The following trick is a work arround that cannot fail at all (until the point it will fail):
sol ksh/bash $ printf '\034a\034b\034c' | awk 'BEGIN{FS=sprintf("%c",28)}{print NF}'
4
The above works because we let awk set the FS using the sprintf function where we pass the decimal number 28=x1c=034
Well $'\x1c' is a bashizm, the portable format is "$(printf '\034')".
(This answer has already been written as a comment.)
When awk has issues, try Perl
$ cat -vT tonyren.txt
a^\b^\c^\d
p^\q^\r^\s
x^\y^\z
$ perl -F"\x1c" -le ' { print scalar #F } ' tonyren.txt
4
4
3
$

Assign bash variables from one awk command?

Hoping someone can help me make my awk commands more efficient please!
Let's say my text file has around 30 lines of this type of thing:
ENTIRE:11.3.28.4.0
OSVER:Solaris11
VARFREE:3G
I'm assigning these to variables in a bash script like this:
ENTIRE=$(awk -F\: '$1 ~ /ENTIRE/ {print $2}' $HOSTFILE)
RELEASE=$(awk -F\: '$1 ~ /RELEASE/ {print $2}' $HOSTFILE)
OSVER=$(awk -F\: '$1 ~ /OSVER/ {print $2}' $HOSTFILE)
Because I have around 30 of these, it means awk is run 30 times, which is slow, and clearly not the best way.
Can anyone suggest how I can build these into one awk command please?
Thanks in advance!
You don't need awk at all. If modifying the original file isn't an option, use a while loop and the declare command to define each variable.
while IFS=: read name value; do
declare "$name=$value"
done < "$HOSTFILE"
An example:
$ IFS=: read name value <<< "foo:bar"
$ declare "$name=$value"
$ echo "$foo"
bar

Awk string extraction not working with variable [duplicate]

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.

How to pass variable to awk [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Using awk with variables
The following command is wrong, the point is I want to use $curLineNumber in awk, how can I do it? Any solution?
curLineNumber = 3
curTime=`ls -l | awk 'NR==$curLineNumber {print $NF}'`
Thanks
curTime=$(ls -l | awk -v line=$curLineNumber 'NR == line { print $NF }'
The -v option is used to specify variables initialized on the command line. I chose the name line for the awk variable.

Resources