accessing variable outside awk in linux - linux

file= input.txt
br=0
awk -v 'BEGIN{FS=";"}
{
for(i=1;i<=NF;i++)
{
print $i
br = NF
}
}'<$file
print "value of br " $br
I am storing the value of NF in br, so that i can use it further in script. In my case the value of NF is 10. but in br I am receiving 0.

You are confusing shell scripts and awk, which are different programs/interpreters.
What happens in awk stays in awk.
The best you can do is print a string to the shell.
I note that I did not need the -v tag, and substituted the -F tag for setting FS.
In your case you might use the END directive in awk, which only runs at the the end.
file= input.txt
br=0
gawk -F; '
{
for(i=1;i<=NF;i++)
{
print $i
br = NF
}
}
END { print "final value of br:"br } '<$file
If you need this number in a shell environment variable called br, you could do it this way:
file= input.txt
br=$( gawk -F; '
{
for(i=1;i<=NF;i++)
{
br = NF
}
}
END { print br } '<$file
)
How It Works
In bash shell
VARNAME=$( command )
runs the command and sets the environment variable VARNAME to the output from running the command.
Important: Use source instead of executing to set variables from shell scripts
Note that if you stick this in br.sh and chmod 700 br.sd, you might be tempted to run it with ./br.sh which will run it, but it will set shell variable $br in the resulting temporary child process, not the calling parent. The parent will have $br empty in that case. To get $br set in the parent, you would have to run the command file with source br.sh not by executing it directly.

Related

Variables with ssh and awk with perl

Trying to execute remotely a bunch of commands in a perl script
This looks like that :
$CMD1 = "/usr/sbin/mminfo -av -q \"savetime>'-1 day 18:00:00',savetime<'17:59:59'\" -r \"ssid,totalsize,nfiles,pool\"|grep \"xxxxx\"|/usr/bin/awk '!seen[\$1]++'";
print Dumper $CMD1;
$CMD = "/usr/bin/ssh xxxx\#$SRV \'$CMD1\' 2>&1";
print Dumper $CMD;
But I still have problem with the $1 in the awk command, It seems to be cancelled when running.
What I can see :
$VAR1 = '/usr/sbin/mminfo -av -q "savetime>\'-1 day 18:00:00\',savetime<\'17:59:59\'" -r "ssid,totalsize,nfiles,pool"|grep "xxxxxx"|/usr/bin/awk \'!seen[$1]++\'';
$VAR1 = '/usr/bin/ssh xxxxx#\'xxxxxx\' \'/usr/sbin/mminfo -av -q "savetime>\'-1 day 18:00:00\',savetime<\'17:59:59\'" -r "ssid,totalsize,nfiles,pool"|grep "xxxxx"|/usr/bin/awk \'!seen[$1]++\'\' 2>&1';
So the '$1' of the awk command is passed correctly to the remote but when running :
#RESU = `$CMD`;
print Dumper #RESU;
I can see that my $1 is missing (or interpretated by the remote shell as a null value) :
$VAR1 = 'awk: ligne de commande:1: !seen[]++
';
$VAR2 = 'awk: ligne de commande:1: ^ syntax error
';
$VAR3 = 'awk: ligne de commande:1: error: expression indice non valide
';
I've tried many things like quoting or double-quoting the string, creating the string with perl 'qq' function, putting value of $CMD1 directly in $CMD and escaping quotes but no way.
And of course, my awk is piped to another awk (not provided here).
I don't want a solution which runs awk localy since I've millions lines returned from the 'mminfo' command.
Any clue (or a better way to do that !) ?
You might want to break it into smaller pieces for readability, and use the multi-arg invocation of system to avoid perl having to spawn a shell. The q() function goes a long way toward avoiding quoting hell.
$mminfo = q{/usr/sbin/mminfo -av -q "savetime>'-1 day 18:00:00',savetime<'17:59:59'" -r "ssid,totalsize,nfiles,pool"};
$awk = q{/usr/bin/awk '/xxxxx/ && !seen[$1]++');
print Dumper [$mminfo, $awk];
#cmd = ( "/usr/bin/ssh", "xxxx\#$SRV", "$mminfo | $awk" );
print Dumper \#cmd;
system #cmd;
Even if you can not use modules in your final environment, you may be able to use them in your local machine. In that case you can use them to quote the command programmatically and then just copy and paste the quoted string into the script you are developing. For instance:
use strict;
use warnings;
use Net::OpenSSH;
my $quoted_cmd1 = Net::OpenSSH->shell_quote('/usr/sbin/mminfo', '-av',
-q => q(savetime>'-1 day 18:00:00',savetime<'17:59:59'),
-r => 'ssid,totalsize,nfiles,pool',
\\'|',
'grep', 'xxxxx',
\\'|',
'/usr/bin/awk', '!seen[$1]++');
my $SRV = "foo";
my $quoted_cmd = Net::OpenSSH->shell_quote('/usr/bin/ssh', "xxxx\#$SRV",
$quoted_cmd1,
\\'2>&1');
print "$quoted_cmd\n";
Which outputs...
/usr/bin/ssh xxxx#foo '/usr/sbin/mminfo -av -q '\''savetime>'\''\'"''"'-1 day 18:00:00'\''\'"''"',savetime<'\''\'\''17:59:59\'\'' -r ssid,totalsize,nfiles,pool | grep xxxxx | /usr/bin/awk '\''!seen[$1]++'\' 2>&1

Change Shell script variable value inside AWK conditional block

I want to update mystatus shell variable to new value inside my awk code.
but I guess the syntax isn't right,
also I have tried declare or eval , but nothing works
hi please help me with this
my code:
mystatus="resolved" -- shell variable
awk 'BEGIN { print "<table>" } -- awk code to write in new file
{
print "<tr><td>" $1 "</td><td>" $2 "</td><tr>"
if ($1=="stopped") mystatus="problem" -- change shell variable value
}
END { print "</table>" }' filestats.txt > email.html
echo $mystatus -- variabe value not getting changed.
Something like this (untested):
mystatus="resolved" # shell variable
awk '
BEGIN { print "<table>" } # awk code to write in new file
{
print "<tr><td>" $1 "</td><td>" $2 "</td><tr>"
if ($1=="stopped") {
mystatus="mystatus.txt"
print "problem" > mystatus # write to a file instead
close(mystatus)
} # I WAS MISSING I WAS MISSING I WAS MISSING I WAS MISSING I WAS MISSING
}
END { print "</table>" }' filestats.txt > email.html
read mystatus < mystatus.txt # read the status from the file
echo $mystatus # variabe value not getting changed.
Some bash purist could comment if this is any way to read from a file to a variable?

Function name in sh

I am trying to extract the current running function name to generate logs for assertion. here is what i have tried
function_name()
{
s=${FUNCNAME[0]}
touch ${s}
}
I think the ${FUNCNAME[0]} only works in bash not in sh.
Is there any way to get the current running function name in sh
One way to do it is to insert the logging expressions manually into every function, that's tedious but it can be automated with awk.
Assume you obey the coding conventions you used in the question:
#!/usr/bin/awk
/^[ \t]*function[ \t]*[a-zA-Z_][^(]*\(\)/ {
name=$0
sub(/^[ \t]*function[ \t]*/, "", name)
sub(/[ \t]*\(\).*/, "", name)
if ($0 !~ /\{/) {
print
getline
}
print
print " s='" name "'"
print " touch ${s}"
next
}
1
The code is self-explanatory, for each function in the sh script, it parses the function name, and insert the logging code below. Note the last line in the above code, which means print out all the other lines.

bash script - why value is set under function and not set outside the function

The following bash script's goal is to read CSV file ( all_words.CSV ) and print parameters and values but I have very strange problem.
When I run the script all words parameters (word1-word8) was printed - until now every thing is fine!When I want to print as word1=$word1 outside of function then from some reason word1 not get the value?
Why all parameters (word1-word8) print the values in function, and when I want to print word1 outside the function then word1 is without value?
I tried with export command but it doesn’t help as; export word1=$word1
Please advice how it can be? What the problem here?
#!/bin/bash
read_csv ()
{
CSV_LINE=2
vars=()
c=1
while IFS=, read -ra arr; do
if ((c==1)); then
vars+=("${arr[#]}")
elif ((c==CSV_LINE)); then
for ((i=0; i<${#arr[#]}; i++)); do
declare ${vars[$i]}="${arr[$i]}"
done
fi
((c++))
done < all_words.CSV
echo CSV_LINE=$CSV_LINE
echo word1=$word1
echo word2=$word2
echo word3=$word3
echo word4=$word4
echo word5=$word5
echo word6=$word6
echo word7=$word7
echo word8=$word8
}
read_csv
echo word1=$word1
.
more all_words.CSV
word1,word2,word3,word4,word5,word6,word7,word8
&^#G TR /erfernfjer *&^NHY " "" ? / $#H,#Y^%" E "R$%*&*UJ,**U&^#%%#$^&// \\,^T%!#&^YG.+___KI*&HHTY,%%#$#!%^#&,P/\06E87*UHG11#
,edehu234##!&,~hum&T%6e4
example of script output:
./readWords_from_csv.bash
CSV_LINE=2
word1=&^#G TR / erfernfjer *&^NHY " "" ? / $#H
word2=#Y^%" E "R$%*&*UJ
word3=**U&^#%%#$^&//\\
word4=^T%!#&^YG.+___KI*&HHTY
word5=%%#$#!%^#&
word6=P/\06E87*UHG11#
word7=edehu234##!&
word8=~hum&T%6e4
word1=
man bash explains under declare:
When used in a function, declare makes NAMEs local, as with the local command.
declare -g ${vars[$i]}="${arr[$i]}"
# ^^
Use declare -g to declare a variable at global level in a function. From man bash:
declare [-aAfFgilrtux] [-p] [name[=value] ...]
[...] The -g option forces
variables to be created or modified at the global scope, even
when declare is executed in a shell function. It is ignored in
all other cases. [...]
Here is a simple demonstration of the -g flag (works as expected on GNU bash, version 4.2.37):
#!/bin/bash
function f() {
declare -g V
V="hello"
}
f
echo $V
Please advice ...
Better use printf:
printf -v "${vars[$i]}" "%s" "${arr[$i]}"
Although I'd suggest using an associative array instead. It's the more appropriate solution:
#!/bin/bash
declare -A CSV_VALUES
declare -a CSV_KEYS
function read_csv {
CSV_VALUES=() CSV_KEYS=()
local VALUES I
{
IFS=, read -ra CSV_KEYS
IFS=, read -ra VALUES
} < all_words.csv
for I in "${!CSV_KEYS[#]}"; do
CSV_VALUES[${CSV_KEYS[I]}]=${VALUES[I]}
done
}
read_csv ## Perhaps pass the filename to read_csv as an argument instead?
# We can do for KEY in "${!CVS_VALUES[#]}" but the order is uncertain.
for KEY in "${CSV_KEYS[#]}"; do
echo "CSV_VALUES[$KEY]=${CSV_VALUES[$KEY]}"
done

How to return data from a bash shell script subroutine?

Given the following two executable scripts:
----- file1.sh
#!/bin/sh
. file2.sh
some_routine data
----- file2.sh
#!/bin/sh
some_routine()
{
#get the data passed in
localVar=$1
}
I can pass 'data' to a subroutine in another script, but I would also like to return data.
Is it possible to return information from some_routine?
e.g: var = some_routine data
Have the subroutine output something, and then use $() to capture the output:
some_routine() {
echo "foo $1"
}
some_var=$(some_routine bar)
It's not allowed, just set the value of a global variable (..all variables are global in bash)
if
some_routine() {
echo "first"
echo "foo $1"
}
some_var=$(some_routine "second")
echo "result: $some_var"
they are ok.But the result seems to be decided by the first "echo".Another way is use "eval".
some_var return "first"
some_routine()
{
echo "cmj"
eval $2=$1
}
some_routine "second" some_var
echo "result: $some_var"
in this way, some_var return "second".The bash don't return a string directly.So we need some tricks.

Resources