Reading 3 consecutive lines with awk? (Or something else) - batch-file

I have a huge file, and at some point it goes like this:
Bla bla bla
LAST ITERATION: 1780 6 12 0.689655172413793
-8708.81862246834 -8698.33572943212 -2003.09638506407
-9.912281246897692E-003
Bla bla bla
I would like to get all the numbers after "LAST ITERATION:" and put it in a line in a file.
I have managed to get the two first lines with this:
awk 'a && NR==n{ print a,b,c,d,$1,$3 } /LAST ITERATION:/{ a=$3; b=$4; c=$5; d=$6; n=NR+1 }' ./$FOLDER/$NAMEDATA >> $NAMEOUTPUT
But I can't seem to find a way to get the last number which is on the 3rd line. Could anyone help me?
Thanks!

If you are using gawk, where RS can be more than one character, an easier approach would be to use "LAST ITERATION:" as the record separator, and print the first 8 fields of the second record, with a space as the output record seperator:
gawk 'BEGIN{RS="LAST ITERATION:";ORS=" "}NR==2{for(n=1;n<=8;++n)print$n}'
Demo: https://ideone.com/UzwkdN

You might use getline Variable to access future lines, I would use GNU AWK for this task following way, let file.txt content be
Bla bla bla
LAST ITERATION: 1780 6 12 0.689655172413793
-8708.81862246834 -8698.33572943212 -2003.09638506407
-9.912281246897692E-003
Bla bla bla
then
awk '/LAST ITERATION/{getline x1;getline x2;line=$0 " " x1 " " x2;sub(/LAST ITERATION:[[:space:]]+/,"",line);gsub(/[[:space:]]+/," ",line);print line}' file.txt
gives output
1780 6 12 0.689655172413793 -8708.81862246834 -8698.33572943212 -2003.09638506407 -9.912281246897692E-003
Explanation: when LAST ITERATION is encountered I save next line to variable x1 and next next line to variable x2, then construct line from space-sheared current line, next line and next next line, then remove LAST ITERATION: and following whitespaces characters using sub function and alter multiple whitespace characters to single spaces using gsub, after doing that I print said line. Disclaimer: this solution assumes there are always at least 2 lines after line with LAST ITERATION.
(tested in gawk 4.2.1)

If you are using regular awk, you can concatenate the 3 lines starting with the line with LAST ITERATION: to a variable, and split it in the end:
awk 'BEGIN{ORS=" "}/LAST ITERATION:/{n=NR+3}NR<n{s=s$0}END{split(s,a);for(i=3;i<11;++i)print(a[i])}'

If I read your question correctly, you say you want to see an entry within a file, followed by two following lines.
Next to that, you seem to want to work with awk.
My answer is: "Why awk? This can very easily be done using grep.", as follows:
grep has three switches to add more lines, next to the matching one:
-A n : add "n" lines after the match
-B n : add "n" lines before the match
-C n : add "n" lines, combined after and before
So, you can simply use grep -A 2 "match" filename.
Good luck

For batch you can target lines using findstr:
The below can target single lines, consecutive lines or a list of lines.
#Echo off
REM :: CALL %0 <filepath> <integer|integer list>
Set "File.Name="
If exist "%~f1" (
Set "File.Name=%~f1"
)Else (
1>&2 Echo(File Not Found
Exit /B 1
)
If "%~2" == "" (
1>&2 Echo(Missing Arg/s for target Line/s.
Exit /B 2
)
Set Target.Lines=%*
Set "Target.Lines=%Target.Lines:"=%"
For /f "Delims=" %%G in ('CMD /V:ON /C "Echo(!Target.Lines:%~1 =!"')Do Set "Target.Lines=%%G"
Set "Line.Count=0"
Set "Highest.Target=0"
Setlocal EnableExtensions EnableDelayedExpansion
For %%G in (%Target.Lines%)Do if !Highest.Target! LSS %%G Set "Highest.Target=%%G"
Endlocal & Set "Highest.Target=%Highest.Target%"
For /f "Tokens=1* Delims=:" %%G in ('%SystemRoot%\System32\findstr.exe /VNLC:"{false.string[%~n0]}" "%File.Name%"')Do (
Set "Line.Count=%%G"
For %%i in (%Target.Lines%)Do if %%G EQU %%i Echo(%%H
)
If %Line.Count% LSS %Highest.Target% (
1>&2 Echo(Lines missing. Lines in file: %Line.Count%. Highest Target: %Highest.Target%
)

awk '
gsub(/LAST ITERATION:/,""){
gsub(/^ */,"");
o=sprintf("%s ",$0);
while(getline && $1 ~ /^[-]?[0-9]+(\.[0-9]*)?/) {
o=o sprintf("%s ", $0)
}
print gensub(/ */," ", "g", o) > "output_file"
}
' input_file
$ cat output_file
1780 6 12 0.689655172413793 -8708.81862246834 -8698.33572943212 -2003.09638506407 -9.912281246897692E-003

Related

bash create for loop with an array variable

i am trying to make output of a command be read by a for loop, but in such a way that the loop variable would be an array. is that possible?
this is what I've been trying so far:
function samplevals() {
echo '"aa bb"'
echo '"cc dd"'
echo '"ee ff" "gg hh"'
}
samplevar='"aa bb"
"cc dd"
"ee ff" "gg hh"'
echo call function samplevals:
for x in `samplevals `; do echo ">$x<"; done
echo read variable samplevar:
echo $samplevar
for x in $samplevar; do echo ">$x<"; done
echo process output of 'echo samplevar:'
for x in `echo $samplevar`; do echo ">$x<"; done
echo "the thing with set"
for x in $samplevar; do set -- $x ; echo "\$1=>$1<,\$2=>$2<"; done
but the output is always the same:
>"aa<
>bb"<
>"cc<
>dd"<
>"ee<
>ff"<
>"gg<
>hh"<
Can I somehow prevent bash from splitting the elements into smaller pieces?
Along the lines of chepner's answer, using read command. The -a flag part of the command lets the output to written out to an array.
IFS=$'\t' read -ra arrayDef < <(echo -ne '"abc def"\t"ghi jkl"')
for x in "${arrayDef[#]}"; do
echo ">$x<"
done
You can replace the echo part with some command that generates such a string. Remember to update the IFS appropriately as to how the string is de-limited. In my case, I just a have the string de-limited by \t
The way to define an array in bash is
samplevars=("aa bb" "cc dd" "ee ff" "gg hh")
for x in "${samplevars[#]}"; do
echo ">$x<"
done

Syntax quirk on assigning a string with parentheses to a variable within an IF block

Below is a BAT file sample which shows a curious behaviour. When a "SET" is used inside () an IF statement we get an error, if we have other code besides a SET then no problem.
I created a work around by doing the SET on the IF line and doing the other logic I need in a normal
IF ... ( stuff ) ELSE ( more )
Does someone know what is going on here?
NB: Same outcome if SETLOCAL is used
::SETLOCAL ENABLEDELAYEDEXPANSION
echo **This works**
#set InstallerTest=false
#IF "%InstallerTest%"=="true" #SET SESign_Exe=%ProgramFiles(x86)%\Schneider Electric\CodeSign\signtrue.exe
#IF NOT "%InstallerTest%"=="true" #SET SESign_Exe=%ProgramFiles(x86)%\Schneider Electric\CodeSign\signfalse.exe
SET SESign_Exe
ECHO **THIS PRODUCES NO ERROR**
#IF "%InstallerTest%"=="true" (
echo IN TRUE PART
) ELSE (
ECHO IN FALSE PART
)
echo **this produces : \Schneider was unexpected at this time.**
#IF "%InstallerTest%"=="true" (
SET SESign_Exe=%ProgramFiles(x86)%\Schneider Electric\CodeSign\signtrue.exe
) ELSE (
SET SESign_Exe=%ProgramFiles(x86)%\Schneider Electric\CodeSign\signfalse.exe
)
::ENDLOCAL
Open a command prompt window and execute there cmd /?. At bottom of the last help page output into the console window you can read which characters in strings require surrounding double quotes: the space character and &()[]{}^=;!'+,`~
The reason is easy to understand. The space character is the separator for the "words" (commands, options, parameters, keywords, ...) on command line.
The other characters have special meanings in Windows command line syntax. A not escaped and not in quoted string defined ( marks beginning of a block an ) marks end of a block if not escaped or within a quoted string.
Therefore you need
set "SESign_Exe=%ProgramFiles(x86)%\Schneider Electric\CodeSign\signtrue.exe"
And you should really use always set "variable=value".
See for example answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? for an explanation with an example why using set "variable=value" is always better than using just set variable=value.

Bash script array to csv

I want to do comma separated string from my array. In my script i collecting data to array outputArr and then i want to echo it to check it out, but now i'm stuck. I want to print it on console using:
echo ${outputArr[*]}
But i'm getting wrong output. So i'm trying to debug it and write it like this:
echo ${outputArr[0]}
echo ${outputArr[1]}
echo ${outputArr[*]}
echo "-------------"
OK here is my output:
Terminally Yours
2204
2204nally Yours
-------------
and other example:
Alfa
1491
1491
-------------
Why this is overwritten with space in the beginning? Of course my goal is (finally):
Alfa;1491
In this point:
Alfa1491
EDIT:
while read -r line
do
singleLine=$line
if [[ $singleLine =~ $regexVenueName ]]
then
singleLine=${singleLine/<span id=\"ctl00_MainContent_lbPartner\" class=\"Partner\">/}
singleLine=${singleLine/<\/span> <br \/><br \/>/}
partnerVenueNameOutput+="$singleLine"
outputArr[0]=$singleLine
fi
done < "$f"
Your array contains elements with carriage returns:
$ foo=($'\rterminally yours' $'\r2204')
$ echo "${foo[0]}"
terminally yours
$ echo "${foo[1]}"
2204
$ echo "${foo[*]}"
2204inally yours
For your code, you can add the following to remove the carriage return from the variable:
singleLine=${singleLine//$'\r'/}
To remove any trailing carriage returns from each array element, try
outputArray=( "${outputArray[#]%$'\r'}" )
However, it would probably be better to examine how outputArray is set in the first place and prevent the carriage returns from being added in the first place. If you are reading from a file that uses DOS line endings, try "cleaning" it first using dos2unix.

batch: multiple FOR parameter taken from command arguments

this is what I'm trying to do
find.bat:
#echo off
SET for_argument=%1
SET other_argument2=%2
SET other_argument3=%3
FOR %%A IN (%for_argument%) DO (
echo %%A
rem do other stuff
)
What I want to do is call
find.bat "1 2 3 4" arg2 arg3
and I want that FOR to be executed with 1 2 3 4 as separated arguments, so that the output is
1
2
3
4
But unfortunately with this code the output is
"1 2 3 4"
Can you help me?
Thanks!
SET "for_argument=%~1"
So you get in the for argument a b c d, but without the quotes, this is important for the FOR loop.
A quoted string like "a b c d" is handled as one token, but a b c d is split into four tokens, allowed delims are space "," ";" or "=".

using 'set' variables that are gawk one liners

i am writing a short bat file that contours a xyz file with GMT utilities (generic mapping tool) i want to read the max and min file and use it later in the bat file what i did is
set max_color=gawk "BEGIN {max = 0} {if ($3>max) max=$3} END {print max}" %file%
set min_color=gawk "BEGIN {min = %max_color%} {if ($3'<'min) min=$3} END {print min}" %file%
but when i try reading it later
makecpt -Crainbow -T%min_color%/%max_color%/10 > conc.cpt
instead of reding the value it has the whole gawk one liner
how can i set a value
use a for loop to get the results of the gawk command, eg
for /f %%a in ('your gawk command') do (
set var=%%a
)

Resources