Change Shell script variable value inside AWK conditional block - linux

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?

Related

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.

How can I stop this Perl command from printing XML declarations over and over again?

I'm runing the following command in Red Hat Linux:
perl -ne '
print "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
while(/(<PRINTKIT FORM_ID=\"PP_WELCOMEKIT\">.*?<\/PRINTKIT>)/g){
print "<sf><XDF>$1</XDF></sf>"
};
' $1 > $2.$TS2.postscrub
$2 is a file name and $TS2 is just a date.
Currently it prints out like 100 lines of
<?xml version=\"1.0\" encoding=\"utf-8\"?>
when I actually don't want it to print any at all.
Can someone change the code above to do everything it is doing except not print <?xml version=\"1.0\" encoding=\"utf-8\"?> anymore? I have already tried just removing the print statement with that line like follows:
perl -ne '
while(/(<PRINTKIT FORM_ID=\"PP_WELCOMEKIT\">.*?<\/PRINTKIT>)/g){
print "<sf><XDF>$1</XDF></sf>"
};
' $1 > $2.$TS2.postscrub
Doing this makes it output a 0 byte file so I know it doesn't work.
Really - please don't use regular expressions for manipulating XML. It's very very nasty and as you've discovered - prone to breaking inexplicably.
Try something like this instead ( I have made a guess at your sample data ).
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
sub replace_printkit {
my ( $twig, $pk ) = #_;
my $sf = $twig->root->insert_new_elt('sf');
$sf->insert_new_elt( 'XDF', $pk->trimmed_text );
$pk->delete;
}
my $twig = XML::Twig->new(
'pretty_print' => 'indented',
'twig_handlers' => { 'PRINTKIT' => \&replace_printkit }
);
$twig->parse( \*DATA );
$twig->set_xml_version('1.0');
$twig->set_encoding('utf-8');
$twig->print;
__DATA__
<xml>
<PRINTKIT FORM_ID="PP_WELCOMEKIT">some_stuff_here</PRINTKIT>
</xml>
This prints:
<?xml version="1.0" encoding="utf-8"?>
<xml>
<sf>
<XDF>some_stuff_here</XDF>
</sf>
</xml>
You may have to amend it slightly for your input data.
Edit:
When you use $twig->print can I place this into a file? If so what is the command to do so?
open ( my $output_fh, '>', "new_file.xml" ) or die $!;
print {$output_fh} $twig -> sprint;
close ( $output_fh );
perl -ne'
BEGIN { print "<?xml version=\"1.0\" encoding=\"utf-8\"?>"; }
while(/(<PRINTKIT FORM_ID=\"PP_WELCOMEKIT\">.*?<\/PRINTKIT>)/g){
print "<sf><XDF>$1</XDF></sf>"
}
' $1 > $2.$TS2.postscrub
or
perl -ne'
print "<?xml version=\"1.0\" encoding=\"utf-8\"?>" if $. == 1;
while(/(<PRINTKIT FORM_ID=\"PP_WELCOMEKIT\">.*?<\/PRINTKIT>)/g){
print "<sf><XDF>$1</XDF></sf>"
}
' $1 > $2.$TS2.postscrub
or
perl -e'
print "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
while (<>) {
while(/(<PRINTKIT FORM_ID=\"PP_WELCOMEKIT\">.*?<\/PRINTKIT>)/g){
print "<sf><XDF>$1</XDF></sf>"
}
}
' $1 > $2.$TS2.postscrub
The advisability of using regexes for XML aside, the simple answer to this question: "How can I stop this Perl command from printing XML declarations over and over again?" is to wrap the XML declaration in a BEGIN block.
BEGIN { print "<?xml version=\"1.0\" encoding=\"utf-8\"?>" }
perlrun describes the effect of the -n switch:
causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed -n or awk
LINE:
while (<>) {
... # your program goes here
}
So whatever you put in the body of an -n program will be run for each line of input, thus repeatedly printing the XML tag. It won't do that if you wrap it with BEGIN.
However, -n behavior is so established for Perl, and repeating the XML tag is so non-standard for XML, it's a wonder this has ever fit anybody's idea of a solution. I would almost suspect that somebody who didn't know what it was doing, removed the BEGIN block, simply because it's such an obvious candidate for one.
You have to leave the parameter -n. It adds a while loop around your code. You just have a working while loop, change it to read all lines (while (<>)) and you can put your condition after your print statement, like this:
perl -e '
print "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
while(<>) {
print "<sf><XDF>$1</XDF></sf>" if(/(<PRINTKIT FORM_ID=\"PP_WELCOMEKIT\">.*?<\/PRINTKIT>)/g);
};' $1 > $2.$TS2.postscrub

Embedding into a shell script an awk program with a single quote in it

I have a one line text file nik.txt and a simple awk script as follows:
LagartijaNick>cat nik.txt
hey the're
LagartijaNick>cat tmp.awk
BEGIN {}
{
searchName=tolower($0);
if ( searchName ~ /'re/ ) {
print $0
}
}
LagartijaNick>awk -f tmp.awk nik.txt
hey the're
This above awk script prints the entire record as expected. But now I have to embed the awk into a BASH script, like so:
#!/bin/bash
infile=$1
function doThis () {
awk 'BEGIN {}
{
searchName=tolower($0);
if ( searchName ~ /'re/ ) {
print $0
}
}' $infile
}
doThis
exit 0
This returns:
./tmp.sh: line 9: syntax error near unexpected token `)'
./tmp.sh: line 9: ` if ( searchName ~ /\'re/ ) {'
Simple, need to escape the single speech mark? But I can't get it to work.
I've tried:
if ( searchName ~ /\'re/ ) {
if ( searchName ~ /''re/ ) {
What am I doing wrong? All I get are syntax error ...
I'm on the following version of bash:
LagartijaNick>/bin/bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Incorporating the suggestion of setting a variable with the single quote and removing the unnecessary BEGIN:
#!/bin/bash
infile=$1
function doThis () {
read -d '' cmd <<EOA
awk -vQ="'" '
{
searchName=tolower(\$0);
if ( searchName ~ Q"re" ) {
print \$0
}
}' $infile
EOA
eval $cmd
}
doThis
exit 0

accessing variable outside awk in 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.

Replacing values of a file based on a conf file

I have a conf file which has the format of variable="value" where values may have special characters as well. An example line is:
LINE_D="(L#'id' == 'log') AND L#'id' IS NULL"
I have another file F which should replace values based on this conf file. For example, if there is line in F
PRINT '$LINE_D'
it should be replaced by
PRINT '(L#'id' == 'log') AND L#'id' IS NULL'
How can I a program in shell script which takes conf and F and generate the values in F replaced.
Thanks
Your definition of what's required leaves lots of gaps, so you'll probably need to tweak this script. It is a cut-down version of a more complex script originally designed to process makefiles. That means there is probably material you could remove from here without causing trouble, though I've gotten rid of most of the extraneous processing.
#!usr/bin/env perl
#
# Note: this script can take input from stdin or from one or more files.
# For example, either of the following will work:
# cat config file | setmacro
# setmacro file
use strict;
use warnings;
use Getopt::Std;
# Usage:
# -b -- omit blank lines
# -c -- omit comments
# -d -- debug mode (verbose)
# -e -- omit the environment
my %opt;
my %MACROS;
my $input_line;
die "Usage: $0 [-bcde] [file ...]" unless getopts('bcde', \%opt);
# Copy environment into hash for MAKE macros
%MACROS = %ENV unless $opt{e};
my $rx_macro = qr/\${?([A-Za-z]\w*)}?/; # Matches $PQR} but ideally shouldn't
# For each line in each file specified on the command line (or stdin by default)
while ($input_line = <>)
{
chomp $input_line;
do_line($input_line);
}
# Expand macros in given value
sub macro_expand
{
my($value) = #_;
print "-->> macro_expand: $value\n" if $opt{d};
while ($value =~ $rx_macro)
{
print "Found macro = $1\n" if $opt{d};
my($env) = $MACROS{$1};
$env = "" unless defined $env;
$value = $` . $env . $';
}
print "<<-- macro_expand: $value\n" if $opt{d};
return($value);
}
# routine to recognize macros
sub do_line
{
my($line) = #_;
if ($line =~ /^\s*$/o)
{
# Blank line
print "$line\n" unless $opt{b};
}
elsif ($line =~ /^\s*#/o)
{
# Comment line
print "$line\n" unless $opt{c};
}
elsif ($line =~ /^\s*([A-Za-z]\w*)\s*=\s*(.*)\s*$/o)
{
# Macro definition
print "Macro: $line\n" if $opt{d};
my $lhs = $1;
my $rhs = $2;
$rhs = $1 if $rhs =~ m/^"(.*)"$/;
$MACROS{$lhs} = ${rhs};
print "##M: $lhs = <<$MACROS{$lhs}>>\n" if $opt{d};
}
else
{
print "Expand: $line\n" if $opt{d};
$line = macro_expand($line);
print "$line\n";
}
}
Given a configuration file, cfg, containing:
LINE_D="(L#'id' == 'log') AND L#'id' IS NULL"
and another file, F, containing:
PRINT '$LINE_D'
PRINT '${LINE_D}'
the output of perl setmacro.pl cfg F is:
PRINT '(L#'id' == 'log') AND L#'id' IS NULL'
PRINT '(L#'id' == 'log') AND L#'id' IS NULL'
This matches the required output, but gives me the heebie-jeebies with its multiple single quotes. However, the customer is always right!
(I think I got rid of the residual Perl 4-isms; the base script still had a few remnants left over, and some comments about how Perl 5.001 handles things differently. It does use $` and $' which is generally not a good idea. However it works, so fixing that is an exercise for the reader. The regex variable is not now necessary; it was when it was also recognizing make macro notations — $(macro) as well as ${macro}.)

Resources