How do I obtain regex matches of piped command using shell script? - windows

First of all I'm trying to obtain a certain property from a KML file. For now, I tried
ogrinfo C:/test.kml -so -al | findstr "Extent"
which was recommended to me and outputs
Extent: (-100.054053, 33.702234) - (-94.647180, 37.125712)
I would require this in the form
-100.054053,-94.647180,33.702234,37.125712 for which I thought to use regex.
I tried the following just to see what it outputted:
ogrinfo C:/test.kml -so -al | findstr "Extent" | findstr /r /c:"-*[0-9]*\.[0-9]*"
but this still outputs
Extent: (-100.054053, 33.702234) - (-94.647180, 37.125712)
I read somewhere that Windows' FINDSTR only outputs the line where it matched and not the regex matches themselves. Is there some other way of doing it?
If I get that working I would save the matches in different variables somehow in a shell script. I'm no expert in shell scripting but I've been looking around and was thinking of doing something like this
#!/bin/bash
for /f "tokens=*" %%a in ('ogrinfo C:/test.kml -so -al ^| findstr "Extent" ^| findstr /r /c:"-*[0-9]*\.[0-9]*"') do (
echo %%a
#do something
)
done >output
but running this causes the shell to immediately disappears and can't even see the error.

Assumptions
You have a kml file with raw data.
You can extract a single line which starts with "Extent: " to get the values you want
Single line => there is only 1 line with that format in the kml file
The format of that line is:
Extent: (NUMBER1, NUMBER2) - (NUMBER3, NUMBER4)
A number can have the following characters: 0 1 2 3 4 5 6 7 8 9 . -
The output you want is:
NUMBER1,NUMBER3,NUMBER2,NUMBER4
Using Linux tools only, you can do this:
#!/bin/bash
#
datafile="data.kml"
# Ensure the data file exists
if [[ ! -f "$datafile" ]]
then
echo "ERROR: the data file does not exist."
exit 1
fi
# Extract the "Extent:" line
dataline=$(grep "Extent: " "$datafile")
# Make sure the line is of a valid format, and assign the number variables
if [[ $dataline =~ "Extent: ("([0-9.-]+)", "([0-9.-]+)") - ("([0-9.-]+)", "([0-9.-]+)")" ]] && number1="${BASH_REMATCH[1]}" && number2="${BASH_REMATCH[2]}" && number3="${BASH_REMATCH[3]}" && number4="${BASH_REMATCH[4]}"
then
echo "-----DEBUG-----"
echo "line==$dataline"
echo "1==$number1"
echo "2==$number2"
echo "3==$number3"
echo "4==$number4"
echo "-- END DEBUG --"
echo ""
echo "$number1,$number3,$number2,$number4"
else
echo "ERROR: there is no \"Extent: \" line in the data file ($datafile)"
fi
Details:
Everything is done in the if line.
=~ matches the left side with the pattern on the right side.
In the regular expression, you can define sections you want to reuse with ( ).
Ex: abcd(1)efgh(2)ijkl. The sections you can reuse are 1 and 2.
So in the if, each number is surrounded by parentheses.
When the =~ is processed, the BASH_REMATCH array is defined with each section.
The "DEBUG" echo statements can be removed or commented out.
If you have more than one "Extent: ..." in the KML file, you can loop on the lines and process each one at a time.

Related

Check if a PostgresSQL DB Exists with Batch File and Output Custom Values to a Text File

Basically I am trying to check if a certain PostgreSQL DB exists with a batch file from the CMD in Windows. Then output custom results onto a text file within the same location, the text file will contain custom values. But the batch I created keeps giving me this (below), does not create the file and instead outputs this on the cmd:
SET _chk_DB=server
was unexpected at this time.
And I would like to know where I went wrong.
I am a beginner with batch so please do take that into consideration.
SET _chk_DB=server
FOR /F "usebackq" %%S IN (psql.exe -h %_svr% -d %_db% -U %_usr%
-P %_psw%
-Q "set nocount on; select count(*) from dbo.sysdatabases where
[name]='%_dtb%'") DO ( SET _chk_DB=%%S )
IF [%_chk_DB%]==[server]
"1" >> Info.text
else
echo "0" >> Info.txt
IF [%_chk_DB%]==[login]
"1" >> Info.text
else
echo "0" >> Info.txt
IF [%_chk_DB%]==[0]
"1" >> Info.text
else
echo "0" >> Info.txt

how to write an empty line in file from a variable?

In Windows Command Line I normally write empty line in a file with
echo; >> file
However, what I have now is a variable
$param1%
If I want echo to write it in the file I have to do
echo %param1% >> file
HERE IS WHERE THE PROBLEM START :
If I'd like an empty like I'd make
set param1=;
However since the ; is not in contact with the echo word the command is
echo ; >> file
which write the ; in the file...
I need the variable to sometime contains text, and sometime nothing. How can I do it?
if "%param1%"=="" echo;>>file else echo %param1%>>file
If a param1 variable does not exist (the same as set "param1="), then %param1% results to:
In a .bat script: %param1% results to an empty string (a string of zero length);
In a CLI window: %param1% results to the %param1% string.
In a .bat script use (note no spaces surrounding %param1%)
>> file (echo;%param1%)
In a CLI window use
>>file (if not defined param1 (echo;) else echo;%param1%)
Note proper using of parentheses in if-else! For instance, check interesting result of next command:
if ""=="" echo;"THEN branch">>file else echo;"ELSE branch">>file
Output:
==>if ""=="" echo;"THEN branch">>file else echo;"ELSE branch">>file
==>type file
"THEN branch" else echo;"ELSE branch"

Listing files of particular pattern in bash

I have a situation in which i have to list file which is of the type as
databaseName.schemaName#1234sdf2323.lock where _Database_Name and _target_schema_name
_lockFolder are variables
# is a token then it is followed by the random alphanumeric number and the same is end with .lock .
I have acheived this in batch file through the code as
FOR /R %_lockFolder% %%F in (%_Database_Name%.%_target_schema_name%#*.lock) do (
for /f "tokens=1* delims=# " %%G IN ("%%~nF") DO (
SET _no=%%H
)
)
but when i am changing it into bash enviorment so that it can run on unix enviorment
for entry in "${_lockFolder}"/*
do
echo ENTRY "$entry"
name='${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock'
ls -l $name > "${lockFolder}"
if [ "$?" -eq "0" ]
then
echo "Do your work here"
else
echo "No files are there for the given pattern"
fi
# exit 21
done
It is not able to recognize the pattern . The files are present in the folder which i have specified
you can simple write a for loop like,
for file in `find ${lockdir} -name "^${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock$"`
do
echo $file
:
:
your job
done
example,
[root#giam20 unix]# ls
checksumupdator.sh GIAMMEFProcessor.sh GIAMRoleExtractor.sh
GIAMAccountExtractor.sh GIAMMetaDataLoader.sh GIAMRoleLoader.sh
GIAMAccountLoader.sh GIAMOOPControlledAttrExtractor.sh GIAMRoleMappingLoader.sh
GIAMAccountTransferLoader.sh GIAMOOPControlledAttrsLoader.sh
[root#giam20 unix]# find . -name "GIAM*.sh"
./GIAMAccountTransferLoader.sh
./GIAMIntermediateCodeUpgrader.sh
./GIAMServiceUpdator.sh
./GIAMOOPControlledAttrsUpdator.sh
./GIAMRoleUpdator.sh
./GIAMProvisioningPolicyExtractor.sh
./GIAMCompExemptionExtractor.sh
./GIAMApprovalNotificationLoader.sh
In Unix shell scripting, variable references are not resolved in a string that is enclosed in single quotes. Therefore, in this line
name='${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock'
the value will be stored into name literally, including all the ${name} references. It is no surprise then that the pattern is not matched later.
So, just change the single quotes to double quotes:
name="${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock"

Computername variable in cmd

In CMD the following variable will give you the name of the computer: %COMPUTERNAME%
I need a variable that takes a part of the computername.
I need a if statement that checks if the computername contains "KM" at the start and 00 at the end. It should not look at the number between KM and -00
KM100-00
KM200-00
This works here:
echo %computername%| findstr "^KM.*00$" >nul && echo found the right format
You can do this with substring commands, as per the following transcript:
pax> set xyzzy=KM100-00 KM200-00
pax> echo %xyzzy%
KM100-00 KM200-00
pax> echo %xyzzy:~0,2%
KM
pax> echo %xyzzy:~-2,2%
00
pax> if %xyzzy:~0,2%==KM if %xyzzy:~-2,2%==00 echo yes
yes
That final (chained) if statement is the one you're looking for to see if your variable starts with KM and ends with 00.
The expression %X:~Y,Z% will give you the Z characters starting at position Y (zero-based) of the variable X. You can provide a negative value of Y to make it relative to the end of the string.
echo %computername%| findstr /I /b "KM" | findstr /i /e "00" && echo computer name is like KM-XX-00
You can try also with hostname instead of echo %computername%
I recommend you to read this page, which is about substring usage in command prompt.
And why dont you try this;
set str=KM2000-00
echo.%str%
set pre=%str:~0,2%
echo.%pre%
set pst=%str:~-2%
echo.%pst%
IF %pre% == KM( IF %pst% == 00( echo.true ) )
pause

Filtering file using reg exp and concatenate certain lines together (command-prompt)

I have to filter a text file filter.tmp containing two types of lines, this shows the difference:
findstr /r "^[0-9][0-9]*.*$" filter.tmp > filter-numbers.tmp
findstr /r "^[^0-9][^0-9]*.*$" filter.tmp > filter-text.tmp
What I need to do is to append lines containing text together like this and if line does contain number just put it to output file:
IF "current line" contains text THEN
previous line = concatenate "previous line" + "/" + "current line"
ELSE
echo "previous line" >> filter.out
echo "current line" >> filter.out
filter.tmp contains something like:
Hello
World
Foo
Bar
45: this is some line
Trouble
with code
66: another line
filter.out should look like:
Hello/World/Foo/Bar
45: this is some line
Trouble/with code
66: another line
I realize, this is very simple, but I just can not get it working. As I am thinking about it, it would be much easier to use C++....
This is a quite verbatim translation of your pseudocode and your regexes, based on the assumption that »contains numbers« really means »starts with two digits« (which is what your regexes show):
#echo off
setlocal enabledelayedexpansion
set Prev=
for /f "delims=" %%x in (filter.tmp) do (
set "Line=%%x"
if "!Line:~0,2!" GEQ "00" if "!Line:~0,2!" LEQ "99" (
if not "!Prev!"=="" (>>filter.out echo !Prev!)
>>filter.out echo !Line!
set Prev=
) else (
if "!Prev!"=="" (set "Prev=!Line!") else (set "Prev=!Prev!/!Line!")
)
)
if not "!Prev!"=="" (>>filter.out echo !Prev!)
This uses several things. First of all, we need delayed expansion which enables us to manipulate environment variables within the loop. Then we iterate over the lines in the file with for /f. Note that this will skip empty lines in the file, but you cannot avoid that. Inside the for /f loop the variable Line holds the current line and Prev the previous one (if there has been a previous one). I swapped the then and else branches of the condition since numbers at the start of the line are easier to check for than non-numbers.
With the echo you'll notice that I moved the redirection to the start of the line; this is to prevent trailing numbers in Prev or Line from having an effect on the redirection (and also to avoid trailing spaces).
If you're not adverse to PowerShell, you can use the following:
$(switch -Regex -File filter.tmp {
'^\D' { if ($prev) { $prev += "/$_" } else { $prev = $_ } }
'^\d{2}' { if ($pref) {$prev}; $_; $prev = '' }
}
if ($prev) { $prev }
) | Set-Content filter.out

Resources