concatenate two variables from 2 different awk commands in a single echo - shell

Job = grep 'Job:' | awk '{ print $3 }'
Status = grep 'Job Status:' | awk '{ print $3 }'
Both the variables are printed correctly by using two echo statements.I want a result like Job name - status in a single line.I have tried below commands. But its printing only 2nd variable like - status
echo "$Job - $Status"
echo "${Job} - ${Status}"
echo -e "${Job} - ${Status}"
please help!

You can do it with a single awk command:
awk '/Job:/ { job = $3 } /Job Status:/ { status = $3 } END { print job " - " status }' file
If Job: comes before Job Status:
awk '/Job:/ { job = $3 } /Job Status:/ { print job " - " $3; exit }' file
Or vice versa:
awk '/Job Status:/ { status = $3 } /Job Status:/ { print $3 " - " status; exit }' file

I think that should work:
echo $(awk ' /Job:/ { print $3} ' file)" - "$(awk ' /Job Status:/ { print $3} ' file)
but konsolebox's version is probably better, as there is only one awk invocation.

I think you are trying to find out how to get the result of running some command and store it in a variable. Then you want to do that twice and print both variables on the same line.
So the basic syntax is:
result=$(some command)
e.g. if
date +'%Y'
tells you the year is 2014, but you want 2014 in a variable called year, you can do
year=$(date +'%Y')
then you can echo $year like this:
echo $year
2014
So, coming to your actual question, you want two variables, one for the output of each of two commands:
job=$(grep "Job:" someFile | awk '{print $3}')
status=$(grep "Job Status:" someFile | awk '{print $3}')
then you can do:
echo $job $status
and get both things on the same line.
The other answers are saying you can avoid invoking awk twice, which is true, but doesn't explain how to capture the result of running a command into a variable. In general, you don't need to use awk and grep, because this:
grep xyz | awk ...
is equivalent to
awk '/xyz/ {...}'
but uses one fewer processes (i.e. no grep) and therefore fewer resources.
And by the way, you must not put any spaces either side of = in bash either. It is
variable=something
not
variable = something

Related

Appending result of function on another field into csv using shell script, awk

I have a csv file stored as a temporary variable in a shell script (*.sh).
Let's say the data looks like this:
Account,Symbol,Price
100,AAPL US,200
102,SPY US,500
I want to add a fourth column, "Type", which is the result of a shell function "foobar". Run from the command line or a shell script itself:
$ foobar "AAPL US"
"Stock"
$ foobar "SPY US"
"ETF"
How do I add this column to my csv, and populate it with calls to foobar which take the second column as an argument? To clarify, this is my ideal result post-script:
Account,Symbol,Price,Type
100,AAPL US,200,Common Stock
102,SPY US,500,ETF
I see many examples online involving such a column addition using awk, and populating the new column with fixed values, conditional values, mathematical derivations from other columns, etc. - but nothing that calls a function on another field and stores its output.
You may use this awk:
export -f foobar
awk 'BEGIN{FS=OFS=","} NR==1{print $0, "Type"; next} {
cmd = "foobar \"" $2 "\""; cmd | getline line; close(cmd);
print $0, line
}' file.csv
Account,Symbol,Price,Type
100,AAPL US,200,Common Stock
102,SPY US,500,ETF
#anubhavas answer is a good approach so please don't change the accepted answer as I'm only posting this as an answer as it's too big and in need of formatting to fit in a comment.
FWIW I'd write his awk script as:
awk '
BEGIN { FS=OFS="," }
NR==1 { type = "Type" }
NR > 1 {
cmd = "foobar \047" $2 "\047"
type = ((cmd | getline line) > 0 ? line : "ERROR")
close(cmd)
}
{ print $0, type }
' file.csv
to:
better protect $2 from shell expansion, and
protect from silently printing the previous value if/when cmd | getline fails, and
consolidate the print statements to 1 line so it's easy to change for all output lines if/when necessary
awk to the rescue!
$ echo "Account,Symbol,Price
100,AAPL US,200
102,SPY US,500" |
awk -F, 'NR>1{cmd="foobar "$2; cmd | getline type} {print $0 FS (NR==1?"Type":type)}'
Not sure you need to quote the input to foobar
Another way not using awk:
paste -d, input.csv <({ read; printf "Type\n"; while IFS=, read -r _ s _; do foobar "$s"; done; } < input.csv)

How to store output of meminfo command to a variable in shell script

Hi dear friends I have a shell script command for store output of
/proc/meminfo command in some variables and I want to sum these
variables, but I got just this result kB+KB+KB and the code doesn't
work,can anybody help to fix it,thanks
numA=$(grep -m 1 "MemTotal" /proc/meminfo | awk '{ print $2 }')
numB=$(grep -m 1 "MemFree" /proc/meminfo | awk '{ print $3 }')
numC=$(grep -m 1 "Buffers" /proc/meminfo | awk '{ print $4 }')
numD=$(grep -m 1 "Cached" /proc/meminfo | awk '{ print $5 }')
echo "-------------------"
echo $numA $numB $numC $numD
echo " ****--------------------"
numsum=$numB+$numC+$numD
echo "numsum =MemFree+Buffers+Cached=$numsum"
echo $numsum
numminus=$mumA-$numsum
echo "numminus =MemTotal-(MemFree+Buffers+Cached)=$numminus"
numDivide=$numminus/$numA
echo "numDivide =numminus/numA=$numsum"
The whole thing should be a single Awk script. Extracting each field to a separate shell variable so you can use the shell's notoriously poor arithmetic facilities is just crazy. In particular, even if you do get some arithmetic in Bash (though the syntax is different from what you tried), it will still be integer only; so your division result will simply be zero.
awk '/MemTotal/ && !memtotal { memtotal = $2 }
/MemFree/ && !memfree { memfree = $3 }
/Buffers/ &&!buffers { buffers = $4 }
/Cached/ && !cached { cached = $5 }
END (
# Ugh, is this really necessary?
print "-------------------"
print memtotal, memfree, buffers, cached
print " ****-------------------"
numsum=memfree+buffers+cached
print "numsum =MemFree+Buffers+Cached=" numsum
numminus=memtotal-numsum
print "numminus =MemTotal-(MemFree+Buffers+Cached)=" numminus
numDivide=numminus/memtotal
print "numDivide =numminus/memtotal=" numDivide }' /proc/meminfo
If one of the values could be zero, this may require a slightly different approach for pulling out the first match.
I renamed the first four variables; the other three should probably get sensible names instead as well, but I could not quickly understand what you are hoping to calculate.
A somewhat more idiomatic approach for capturing the result of the calculation for later use is to have the Awk script print just the computer-readable output. The following script is rich in comments -- it could be pared down to be much smaller if you remove the comments, but I suppose legibility and maintainability would trump brevity here. Incidentally, this also demonstrates the "slightly different approach" to ensure that we always get the first value of a variable.
memRatio=$(awk '# Populate an associative array with first occurrences
/MemTotal/ && !("memtotal" in i) { i["memtotal"] = $2 }
/MemFree/ && !("memfree" in i) { i["memfree"] = $3 }
/Buffers/ && !("buffers" in i) { i["buffers"] = $4 }
/Cached/ && !("cached" in i) { i["cached"] = $5 }
# Have we collected all the keys for the array? Then print and quit
("memtotal" in i) && ("memfree" in i) &&
("buffers" in i) && ("cached" in i) {
print (i["memtotal"]-i["memfree"]-i["buffers"]-i["cached"])/i["memtotal"]
exit 0 # success
}
# If we fall through to here, we never captured the variables
END { exit 1 }' /proc/meminfo)
Though on my system, all these values seem to be in $2, not in successively increasing columns. In this case, the capturing code could be simplified somewhat (use a single regex for all four keys; use the regex match regardless of case for the array key).
I only modify the scripts so that it returns some values. I am not an expert but i only fixed error that where visible to me. Hope it works for you.
numA=$(grep -m 1 "MemTotal" /proc/meminfo | awk '{ print $2 }')
numB=$(grep -m 1 "MemFree" /proc/meminfo | awk '{ print $2 }')
numC=$(grep -m 1 "Buffers" /proc/meminfo | awk '{ print $2 }')
numD=$(grep -m 1 "Cached" /proc/meminfo | awk '{ print $2 }')
echo "-------------------"
echo $numA $numB $numC $numD
echo " ****--------------------"
numsum=$(($numB+$numC+$numD))
echo "numsum =MemFree+Buffers+Cached=$numsum"
echo $numsum
numminus=$mumA-$numsum
echo "numminus =MemTotal-(MemFree+Buffers+Cached)=$numminus"
numDivide=$numminus/$numA
echo "numDivide =numminus/numA=$numsum"

How do I print the result of a command with 'echo'?

How do print my full name with the following?
awk -F: '($1==U){print $5}' U=$LOGNAME /etc/passwd
Per example, but with the echo command with some words on sides:
For example,
Hello Diogo Saraiva, happy to see you again
Where Diogo Saraiva is my full name which I have in Ubuntu records.
I tried some things, but I have not accomplished that script...
Another thing: Why, when I issue awk -F: '($1==U){print $5}' U=$LOGNAME /etc/passwd, is Diogo Saraiva,,, shown instead of Diogo Saraiva?
This happens too with:
grep $USER /etc/passwd | awk 'BEGIN { FS=":" } { print $5 }'
I need for my script to declare a variable, "like", with the command, and then echo that variable "like" various times along my script.
To output the string you want you can use this command.
awk -F: -v U="$LOGNAME" '$1==U{print "Hello " $5 ", happy to see you again"}' /etc/passwd
If awk -F: -v U="$LOGNAME" '$1==U{print $5}' /etc/passwd is outputting Diogo Saraiva,,, then that is what is in your /etc/passwd file for that field.
To save the output from a command in a variable just use:
var=$(command)
And remember to quote the variable when you use it:
echo "Hello $var, happy to see you again"

How can I pass variables from awk to a shell command?

I am trying to run a shell command from within awk for each line of a file, and the shell command needs one input argument. I tried to use system(), but it didn't recognize the input argument.
Each line of this file is an address of a file, and I want to run a command to process that file. So, for a simple example I want to use 'wc' command for each line and pass $1to wc.
awk '{system("wc $1")}' myfile
you are close. you have to concatenate the command line with awk variables:
awk '{system("wc "$1)}' myfile
You cannot grab the output of an awk system() call, you can only get the exit status. Use the getline/pipe or getline/variable/pipe constructs
awk '{
cmd = "your_command " $1
while (cmd | getline line) {
do_something_with(line)
}
close(cmd)
}' file
FYI here's how to use awk to process files whose names are stored in a file (providing wc-like functionality in this example):
gawk '
NR==FNR { ARGV[ARGC++]=$0; next }
{ nW+=NF; nC+=(length($0) + 1) }
ENDFILE { print FILENAME, FNR, nW, nC; nW=nC=0 }
' file
The above uses GNU awk for ENDFILE. With other awks just store the values in an array and print in a loop in the END section.
I would suggest another solution:
awk '{print $1}' myfile | xargs wc
the difference is that it executes wc once with multiple arguments. It often works (for example, with kill command)
Or use the pipe | as in bash then retrive the output in a variable with awk's getline, like this
zcat /var/log/fail2ban.log* | gawk '/.*Ban.*/ {print $7};' | sort | uniq -c | sort | gawk '{ "geoiplookup " $2 "| cut -f2 -d: " | getline geoip; print $2 "\t\t" $1 " " geoip}'
That line will print all the banned IPs from your server along with their origin (country) using the geoip-bin package.
The last part of that one-liner is the one that affects us :
gawk '{ "geoiplookup " $2 "| cut -f2 -d: " | getline geoip; print $2 "\t\t" $1 " " geoip}'
It simply says : run the command "geoiplookup 182.193.192.4 | -f2 -d:" ($2 gets substituted as you may guess) and put the result of that command in geoip (the | getline geoip bit). Next, print something something and anything inside the geoip variable.
The complete example and the results can be found here, an article I wrote.

getting result from awk and printing it into a file

I am using awk to get compute some sums and I want to store them in a file.
here is my input file:
misses 15
hit 18
misses 20
hit 31
And I want to print the total misses, and total hits in a file.
If I run this:
awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt
I see them in the terminal.
Now I want to write the in a file:
I tried this:
#!/bin/bash
awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt
echo misses $misses > $1; #first one overwrites the previous $1 is the argument given in the command line
echo hits $hits>> $1; # all the othes append to the .txt file
but $misses, and $hits do not have value.
I also tried this:
#!/bin/bash
result= $(echo $output | awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt )
# $NF if I want the last column
echo $result
that I saw on the web, in order to see what $result will return me but I get this error:
./test2.sh: line 2: Hits:: command not found
hits and misses are only variables inside awk, not in the shell after awk exits. Just do the following:
#!/bin/bash
awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt > $1
In your second attempt, you cannot put a space after the '=':
result=$(echo $output | awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt )
simply redirect the output of the awk command:
awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt >file.txt
the redirection operator > can be appended to any shell command to redirect its standard output to a file. changing it to >> appends the command's output to the file instead of completely overwriting the file, as you noticed.
edit:
the reason this didn't work:
#!/bin/bash
awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt
echo misses $misses > $1; #first one overwrites the previous $1 is the argument given in the command line
echo hits $hits>> $1; # all the othes append to the .txt file
is because $misses and $hits are local variables to the awk script. thus the shell has no knowledge of them outside that statment, so when you try to echo them, you get blanks.
and this doesn't work:
#!/bin/bash
result= $(echo $output | awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt )
# $NF if I want the last column
echo $result
for multiple reasons.
1) when assigning variables in bash, you cannot have whitespace around the equal sign, so the second line must begin:
`result=$(echo...`
2) the echo statement inside your substitution (echo $output) is unnecessary. this is because a) $output is undefined so echo produces no output, and b) the second statement in the pipeline (the awk statement) completely ignores the standard output of the command preceding it in the pipeline anyway since you specified a filename for it to act on (t.txt). so the second line could just be:
result=$(awk 'BEGIN { hits=0; misses=0; } /^hit/{ hits+=$2}; /^misses/{misses+=$2}; END {print "Hits: " hits "\nMisses: " misses }' t.txt)
3) the echo statement at the end will display the results all on one line, despite the fact that the awk statement prints two lines. this is because you did not quote the variable in your echo statement. try this instead:
echo "$result"
as a rule in bash scripting, you should ALWAYS quote the variables you are passing or printing, unless you know for sure why you don't want to.
hope that helps you learn a bit more about what you were trying!
Here is a more compact solution:
#!/bin/bash
awk '
{tally[$1] += $2}
END {
for (outcome in tally) {
print outcome ":", tally[outcome]
}
}' t.xt > $1
You don't have to initialize variables in AWK. The first time you use it, AWK will assume 0 for number, or "" for string, depend on the context.

Resources