Is using awk at least 'awk -F' always will be fine? - awk

What is the difference on Ubuntu between awk and awk -F? For example to display the frequency of the cpu core 0 we use the command
cat /proc/cpuinfo | grep -i "^ cpu MHz" | awk -F ":" '{print $ 2}' | head -1
But why it uses awk -F? We could put awk without the -F and it would work of course (already tested).

Because without -F , we couldn't find from wath separator i will begin the calculation and print the right result. It's like a way to specify the kind of separator for this awk's using. Without it, it will choose the trivial separator in the line like if i type on the terminal: ps | grep xeyes | awk '{print $1}' ; in this case it will choose the space ' ' as a separator to print the first value: pid OF the process xeyes. I found it in https://www.shellunix.com/awk.html. Thanks for all.

Related

Using awk to print without double quotes

I would like to get the right value of the following command as a string without double quotes.
$ grep '^VERSION=' /etc/os-release
VERSION="20.04.3 LTS (Focal Fossa)"
When I pipe it with the following awk, I don't get the desired output.
$ grep '^VERSION=' /etc/os-release | awk '{print $0}'
VERSION="20.04.3 LTS (Focal Fossa)"
$ grep '^VERSION=' /etc/os-release | awk '{print $1}'
VERSION="20.04.3
$ grep '^VERSION=' /etc/os-release | awk '{print $2}'
LTS
How can I fix that?
You may use this single awk command:
awk -F= '$1=="VERSION" {gsub(/"/, "", $2); print $2}' /etc/os-release
20.04.3 LTS (Focal Fossa)
1st solution: With your shown samples, please try following awk code.
awk 'match($0,/^VERSION="[^"]*/){print substr($0,RSTART+9,RLENGTH-9)' Input_file
Explanation: Simple explanation would be, using match function of awk to match starting VERSION=" till next occurrence of " and then printing the matched part(to get only desired output as per OP's shown samples).
2nd solution: Using GNU grep with PCRE regex enabled option try following.
grep -oP '^VERSION="\K[^"]*' Input_file
3rd solution: Using awk's capability to set different field separators and then check conditions accordingly and print values.
awk -F'"' '$1=="VERSION="{print $2}' Input_file
Assuming that "the right value" you want output is 20.04.3:
$ awk -F'[" ]' '/^VERSION=/{print $2}' file
20.04.3
or if it's the whole quoted string:
$ awk -F'"' '/^VERSION=/{print $2}' file
20.04.3 LTS (Focal Fossa)
You can use an awk command like
awk 'match($0, /^VERSION="([^"]*)"/, m) {print m[1]}' /etc/os-release
Here, ^VERSION="([^"]*)" matches VERSION=" at the start of the string (^), then captures into Group 1 any zero or more chars other than " (with ([^"]*)) and then matches ". The match is saved in m where m[1] holds the Group 1 value.
Or, sed like
sed -n '/^VERSION="\([^"]*\)".*/s//\1/p' /etc/os-release
See an online test:
s='VERSION="20.04.3 LTS (Focal Fossa)"'
awk 'match($0, /^VERSION="([^"]*)"/, m) {print m[1]}' <<< "$s"
sed -n '/^VERSION="\([^"]*\)".*/s//\1/p' <<< "$s"
Here, -n option suppresses the default line output, /^VERSION="\([^"]*\)".*/ matches a string starting with VERSION=", then capturing into Group 1 any zero or more chars other than ", and then matching " and the rest of the string, and replacing the whole match with the Group 1 value. // means the previous regex pattern must be used. p only prints the result of the substition.
Both output 20.04.3 LTS (Focal Fossa).
Since the file /etc/os-release conforms to a variable assignment in bash or the shell in general (POSIX), sourcing it should do the job.
source /etc/os-release; echo "$VERSION"
Using a subshell just in case one does not want the pollute the current env variables.
( source /etc/os-release; echo "$VERSION" )
Assigning it to a variable.
version=$( source /etc/os-release; echo "$VERSION" )
If the shell you're using does not conform to POSIX.
sh -c '. /etc/os-release; echo "$VERSION"'
See your local man page if available.
man 5 os-release

Multiple awk print in single command

Here are the 2 command which we need to execute, there are two ways to execute this in one line either by ; or |. Is there any other way to execute it via awk command.
These are the below command which is getting executed twice, is it possible to have one command with multiple awk print as shown in the example command tried.
isi_classic snapshot usage | tail -n 1 | awk '{printf "\t\t\tSnapshot USED %=%.1f%%\n", $4}'
Snapshot USED =0.6%
isi_classic snapshot usage | tail -n -1 | awk '{ print "\t\t\tSnapshot USED:" $1}'
Snapshot USED=3.2T
Example command tried:
isi_classic snapshot usage | tail -n 1 | awk '{printf "\t\t\tSnapshot USED %:%.1f%%\n", $4}'; awk '{ print "\t\t\tSnapshot USED:" $1}'
Snapshot USED =0.6%
Snapshot USED=3.2T
You can definitely use one-line command to do it,
isi_classic snapshot usage | awk -v OFS='\t\t\t' 'END{printf "%sSnapshot USED %=%.1f%%\n%sSnapshot USED:%s\n",OFS,$4,OFS,$1}'
Brief explanation,
No need to use tail, awk 'END{}' can do the same thing
You can combine your printf and print command to one
It would be better to substitute the '\t\t\t' as OFS to make the command more readable

Trying to print awk variable

I am not much of an awk user, but after some Googling, determined it would work best for what I am trying to do...only problem is, I can't get it to work. I'm trying to print out the contents of sudoers while inserting the server name ($i) and a comma before the sudoers entry as I'm directing it to a .csv file.
egrep '^[aA-zZ]|^[%]' //$i/etc/sudoers | awk -v var="$i" '{print "$var," $0}' | tee -a $LOG
This is the output that I get:
$var,unixpvfn ALL = (root)NOPASSWD:/usr/bin/passwd
awk: no program given
Thanks in advance
egrep is superfluous here. Just awk:
awk -v var="$i" '/^[[:alpha:]%]/{print var","$0}' //"$i"/etc/sudoers | tee -a "$LOG"
Btw, you may also use sed:
sed "/^[[:alpha:]%]/s/^/${i},/" //"$i"/etc/sudoers | tee -a "$LOG"
You can save the grep and let awk do all the work:
awk -v svr="$i" '/^[aA-zZ%]/{print svr "," $0}' //$i/etc/sudoers
| tee -a $LOG
If you put things between "..", it means literal string, and variable won't be expanded in awk. Also, don't put $ before a variable, it will indicate the column, not the variable you meant.

String concatenation doesn't work in gawk print instruction

I have the following grep and gawk line running in windows
grep ItemDischarged D:\systems\CmcComRouting.log | gawk -v OFS=, "{print $8}" | cut -d ">" -f 1 | uniq -c | gawk -v OFS=, "{print $1,$2}" > d:\03TotalItems.log
the output is as follows
59523,ItemDischargedTlg
What I want to do is add "Lower" to the end of "ItemDischargedTlg" but cannot figure out how to do it, I have tried
{print $1,$2"Lower"}
but it prints nothing.
Thanks
This might do the trick:
gawk -v OFS=, '{$2=$2"Lower";print $1,$2}'
When trying to concatenate strings and commas you should be careful. Commas and concatenation as argument of a print instruction don't go well together.
If on windows, be careful with " and '.

find pattern from log file using awk

[QFJ Timer]:2014-07-02 06:19:09,030:bla.all.com.bla.bla.ppp.xxx.abcsedf:
i would like to extract the date and time.
so the date is no problem :
cat bla.log |awk -F: '{print $2}'|awk '{print $1}'
now the issue is with the time.
if i do : cat bla.log |awk '{print $3}' so i get:
06:19:09,030:bla.all.com.bla.bla.ppp.xxx.abcsedf:
which mean that i need another grep here right?
but i did so many tries using also 'FS' and didn't get only the time.
Can someone please advise?
Thank you.
In the GNU version of awk FS can be a regexp:
echo "[QFJ Timer]:2014-07-02 06:19:09,030:bla.all.com.bla.bla.ppp.xxx.abcsedf:" |
awk -vFS=":|," '{ print $2":"$3":"$4;}'
which spits out
2014-07-02 06:19:09
Your left separator is ':' and the right is ',', and unfortunately hours, minutes and seconds are also separated by your left separator. That is solved by printing $3 and $4. Quick and dirty solution, but it isn't going to be be very robust.
You could use sed for this purpose,
$ echo '[QFJ Timer]:2014-07-02 06:19:09,030:bla.all.com.bla.bla.ppp.xxx.abcsedf:' | sed 's/^[^:]*:\([^,]*\).*/\1/g'
2014-07-02 06:19:09
cat bla.log |awk -F":" '{print $2":"$3":"$4}' | awk -F"," '{print $1}'
Which gets you:
2014-07-02 06:19:09
You can use grep, since it is meant for that:
grep -o '[0-9]\{4\}\(-[0-9]\{2\}\)\{2\}\(\( \|:\)[0-9]\{2\}\)\{3\}' log.file
or, a little bit simpler, egrep:
egrep -o '[0-9]{4}(-[0-9]{2}){2}(( |:)[0-9]{2}){3}' log.file