gawk64 command trobleshooting - gawk

I am trying to trouble shoot an awk script and having trouble with the gawk64 command.
gawk64 -f awkmakearchive.txt -v SPD=abc.csv -v REF=def.csv ijk.csv
In the awkmakearchive.txt file i am getting syntax error for the following
line :
BEGIN {
FS = ","
# Load SPD
spdcount = 0
while (getline < SPD) {
for (i=0; i<96; i++) {
Pattern[$1][i] = $(i+2) ----> Syntax error
}
spdcount++
}
....
...
}
Please help.

Solved! I was using GnuWin32 to run the script instead of GnuWin 64 bit version. GnuWin32 did not have gawk64 in its bin.

Related

Gawk error message fails on invocation line

win7-64
cygcheck 3.1.7
gawk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
gawk outputs an error for the program invocation line. The program works in debug mode (gawk -D -f create) but not from inside my cygwin shell. Other gawk programs work fine. Please tell me what I am doing wrong?
> create 2000_RDA.csv
gawk: cmd. line:1: ./create
gawk: cmd. line:1: ^ syntax error
gawk: cmd. line:1: ./create
gawk: cmd. line:1: ^ unterminated regexp
The program
#! /bin/gawk
BEGIN {
outputLine[1] = " const string ";
outputLine[2] = " [] = { "
outputLine[4] = " , "
outputLine[5] = " }\n"
}
BEGINFILE {
line = 1;
name = "y" gensub(/_RDA.csv$/, "", "g", FILENAME);
printf("%s%s%s", outputLine[1], name, outputLine[2]);
}
ENDFILE {
printf("%s", outputLine[5]);
}
{
if (($0 ~ /^[[:digit:]]/)) { # begins with a number
if (line == 1) { printf("\"%s\"\n", $0); line = 0; }
else { printf("%s\"%s\"\n", outputLine[4], $0); }
}
}
Your shebang line is wrong. To use a file as an awk script, you have to add the -f option:
#!/bin/gawk -f
Shebang lines work by having the pathname of the script file and the arguments passed to the script appended to the line, so running create 2000_RDA.csv becomes /bin/gawk ./create 2000_RDA.csv, which means gawk treats ./create as the awk code to run. Adding the -f makes it /bin/gawk -f ./create 2000_RDA.csv, which will execute the code in the file (Which is now the argument of -f).

PowerShell to remove matching line plus immediately following line

I am trying to convert a “sed” script I use on my FreeBSD machine to one using “Powershell” on Windows 10.
This is the sed script. It is used to strip a header from an email plus the immediately following line and send the output to “email_1.txt”. The file is fed to the script on the command line; i.e. “COMMAND file”
sed '/Received: by 2002:a17:90a:3566:0:0:0:0/,/^/d' <$1> email_1.txt
I cannot find a way to get this to work with “PowerShell”.
Thanks!
You have a couple of options.
Install sed -
Something like scoop might be helpful here.
Write a pure powershell solution.
This will be very similar to what you would write if you were to try to do the same thing in "pure" bash. Here is an attempt to do so:
--
function Delete-TargetLines {
[cmdletbinding()]
param(
[String]$needle,
[int]$count = [int]1,
[parameter(ValueFromPipeline)]
[string[]]$haystack
)
Begin {
[int]$seen = 0
}
Process {
if ($seen -gt 0) {
$seen -= 1
} elseif ( $haystack -match $needle ) {
$seen = 1
} else {
$haystack
}
}
}
And an example of running it:
> #("Pre-line", "This is a test", "second line", "post line") | Delete-TargetLines -needle "test"
Pre-line
post line
> Get-Content $myfile | Delete-TargetLines -needle 'value' > $outfile

Insert a line at the end of an ini section only if it doesn't exist

I have an smb.conf ini file which is overwritten whenever edited with a certain GUI tool, wiping out a custom setting. This means I need a cron job to ensure that one particular section in the file contains a certain option=value pair, and insert it at the end of the section if it doesn't exist.
Example
Ensure that hosts deny=192.168.23. exists within the [myshare] section:
[global]
printcap name = cups
winbind enum groups = yes
security = user
[myshare]
path=/mnt/myshare
browseable=yes
enable recycle bin=no
writeable=yes
hosts deny=192.168.23.
[Another Share]
invalid users=nobody,nobody
valid users=nobody,nobody
path=/mnt/share2
browseable=no
Long-winded solution using awk
After a long time struggling with sed, I concluded that it might not be the right tool for the job. So I moved over to awk and came up with this:
#!/bin/sh
file="smb.conf"
tmp="smb.conf.tmp"
section="myshare"
opt="hosts deny=192.168.23."
awk '
BEGIN {
this_section=0;
opt_found=0;
}
# Match the line where our section begins
/^[ \t]*\['"$section"'\][ \t]*$/ {
this_section=1;
print $0;
next;
}
# Match lines containing our option
this_section == 1 && /^[ \t]*'"$opt"'[ \t]*$/ {
opt_found=1;
}
# Match the following section heading
this_section == 1 && /^[ \t]*\[.*$/ {
this_section=0;
if (opt_found != 1) {
print "\t'"$opt"'";
}
}
# Print every line
{ print $0; }
END {
# In case our section is the very last in the file
if (this_section == 1 && opt_found != 1) {
print "\t'"$opt"'";
}
}
' $file > $tmp
# Overwrite $file only if $tmp is different
diff -q $file $tmp > /dev/null 2>&1
if [ $? -ne 0 ]; then
mv $tmp $file
# reload smb.conf here
else
rm $tmp
fi
I can't help feeling that this is a long script to achieve a simple task. Is there a more efficient/elegant way to insert a property in an ini file using basic shell tools like sed and awk?
Consider using Python 3's configparser:
#!/usr/bin/python3
import sys
from configparser import SafeConfigParser
cfg = SafeConfigParser()
cfg.read(sys.argv[1])
cfg['myshare']['hosts deny'] = '192.168.23.';
with open(sys.argv[1], 'w') as f:
cfg.write(f)
To be called as ./filename.py smb.conf (i.e., the first parameter is the file to change).
Note that comments are not preserved by this. However, since a GUI overwrites the config and doesn't preserve custom options, I suspect that comments are already nuked and that this is not a worry in your case.
Untested, should work though
awk -vT="hosts deny=192.168.23" 'x&&$0~T{x=0}x&&/^ *\[[^]]+\]/{print "\t\t"T;x=0}
/^ *\[myshare\]/{x++}1' file
This solution is a bit awkward. It uses the INI section header as the record separator. This means that there is an empty record before the first header, so when we match the header we're interested in, we have to read the next record to handle that INI section. Also, there are some printf commands because the records still contain leading and trailing newlines.
awk -v RS='[[][^]]+[]]' -v str="hosts deny=192.168.23." '
{printf "%s", $0; printf "%s", RT}
RT == "[myshare]" {
getline
printf "%s", $0
if (index($0, str) == 0) print str
printf "%s", RT
}
' smb.conf
RS is the awk variable that contains the regex to split the text into records.
RT is the awk variable that contains the actual text of the current record separator.
With GNU awk for a couple of extensions:
$ cat tst.awk
index($0,str) { found = 1 }
match($0,/^\s*\[([^]]+).*/,a) {
if ( (name == tgt) && !found ) { print indent str }
name = a[1]
found = 0
}
{ print; indent=gensub(/\S.*/,"","") }
.
$ awk -v tgt="myshare" -v str="hosts deny=192.168.23." -f tst.awk file
[global]
printcap name = cups
winbind enum groups = yes
security = user
[myshare]
path=/mnt/myshare
browseable=yes
enable recycle bin=no
writeable=yes
hosts deny=192.168.23.
[Another Share]
invalid users=nobody,nobody
valid users=nobody,nobody
path=/mnt/share2
browseable=no
.
$ awk -v tgt="myshare" -v str="fluffy bunny" -f tst.awk file
[global]
printcap name = cups
winbind enum groups = yes
security = user
[myshare]
path=/mnt/myshare
browseable=yes
enable recycle bin=no
writeable=yes
hosts deny=192.168.23.
fluffy bunny
[Another Share]
invalid users=nobody,nobody
valid users=nobody,nobody
path=/mnt/share2
browseable=no

awk command to run a C++ code and input several times

Say, I have a C code which I compile like:
$ gcc code.c -o f.out
$ ./f.out inputfile outputfile
Then the code asks for input
$ enter mass:
Now if I need to run this code for example 200 times and the input files have name : 0c.txt, 1c.txt, ....., 199c.txt etc and I want to use same value of mass every time (e.g. mass=6) then how do I write an "awk" command for that? Thanks for your help.
You don't specify your outputfile name. I'll assume 0c.out, 1c.out, ...
I'm also assuming that the f.out program reads the mass from stdin instead of anything more complicated.
#!/usr/bin/gawk -f
BEGIN {
mass = 6
for (i=0; i<200; i++) {
cmd = sprintf("./f.out %dc.txt %dc.out", i, i)
print mass |& cmd
close(cmd, "to")
while ((cmd |& getline out) > 0) {
do something with each line of output from ./f.out
}
close(cmd)
}
}
ref http://www.gnu.org/software/gawk/manual/html_node/Two_002dway-I_002fO.html
In bash, you'd write:
for i in $(seq 0 199); do
echo 6 | ./f.out ${i}c.txt ${i}c.out
done

Reading Trace file from NS2 using gawk

I am new user of gawk. I am trying to read trace file by putting a small code in a file and then by making that file executable. Following is what I am trying to do.
#!/bin/sh
set i = 0
while ($i < 5)
awk 'int($2)=='$i' && $1=="r" && $4==0 {pkt += $6} END {print '$i'":"pkt}' out.tr
set i = `expr $i + 1`
end
after this I am running following command:
sh ./test.sh
and it says:
syntax error: word unexpected (expecting do)
any help?
Assuming you are using bash
Syntax of while loop:
while test-commands; do consequent-commands; done
more info
For comparison using < operator you need to use Double-Parentheses see Shell Arithmetic and Conditional Constructs.
To assign value to the variable you used in the code just write i=0.
To access a shell variable in awk use -v option of awk.
Thus your might be become like this:
i=0
while ((i < 5))
do
awk -v k=$i 'int($2)==k && $1=="r" && $4==0 {pkt += $6} END {print k":"pkt}' out.tr
i=`expr $i + 1`
done
Here the variable k in awk code, has the value of variable $i from shell.
Instead of expr $i + 1 you can use $((i + 1)) or shorter $((++i))
Also you can use for loop then your code becomes much cleaner:
for (( i=0; i < 5; i++ ))
do
awk -v k=$i 'int($2)==k && $1=="r" && $4==0 {pkt += $6} END {print k":"pkt}' out.tr
done