2

This is my input file.

STDEP:DEV=UPDR-5377&&-5407;
UPDR-5381       BUSY                   H'0   ALNEONO     -
UPDR-5382       IDLE                   H'0   ALNEONO     -

UPDR-53770      BLOC  MBL         NC   H'0               -
UPDR-53771      BLOC  MBL         NC   H'0               -
UPDR-53772      BLOC  MBL         NC   H'0               -
UPDR-53773      BLOC  MBL         NC   H'0               -
UPDR-53774      BLOC  MBL         NC   H'0               -

UPDR-5699       LIBL                   H'1   VBYABYO     MAINT
UPDR-5700       LIBL                   H'1   VBYABYO     MAINT
UPDR-5701       LIBL                   H'1   VBYABYO     MAINT
UPDR-5702       LIBL                   H'1   VBYABYO     MAINT

UPDR-4253       BLOC  ABL              H'1   ODUAHRO     MAINT
UPDR-4254       BLOC  ABL              H'1   ODUAHRO     MAINT
UPDR-4255       BLOC  ABL              H'1   ODUAHRO     MAINT
UPDR-6689       BLOC  ABL              H'1   ODUAHRO     MAINT

I need to parse it, get values from each line between 46 and 52. At the end the unique values should be stored in a text file. For this input file the output should be:

type some_file.txt
ALNEONO VBYABYO ODUAHRO

The challenge for me is that it needs to be done in a Windows cmd line. Furthest I've made it is until this step

for /F "tokens=* delims=" %a in (KHMSC4_DELETE_check.txt) do @echo %a:~46,7%

which does not cut line at specified interval. Any idea is highly appreciated.

adiv
  • 46
  • 3
  • Because you want to do this from the cmd line and you need delayed expansion, your command will have to start with `CMD /V:ON /C` – Squashman Jan 18 '16 at 21:18

3 Answers3

1

Variable substring substitution doesn't work with for variables (%a or %%a)

Assuming, your textfile is formatted using spaces, not tabs:

@echo off
setlocal enabledelayedexpansion
rem define output variable (doesn't work with empty varable, so insert a space):
set "output= "
rem parse the file line for line:
for /F "tokens=* delims=" %%a in (somefile.txt) do (
  rem put the line into a variable to work with it:
  set "string=%%a"
  rem get the desired location (again add a space in case the string is empty (line too short)):
  set "string=!string:~45,7! "
  rem remove all spaces (the following line doesn't work as intended when string is empty):
  set "string=!string: =!"
  rem check, if string is already in output, if not add it
  rem by (doing that, replace all double spaces (from short lines) in output with one space)
  rem (again, the "set output=" doesn't work with empty "output")
  echo !output!|find "!string!" >nul || set "output=!output:  = ! !string!"
)
echo the string, stripping the leading space:
echo %output:~1%

This uses substring substitution, explained in set /p, delayed expansion and ||, which works as "if previous command (find) failed, then"

Also note dbenhams comment:

...this will not work properly if any of the lines contain ! ... Also, this will skip lines that begin with ;

I didn't bother with that, because your input file seems not to have this issues.

Community
  • 1
  • 1
Stephan
  • 53,940
  • 10
  • 58
  • 91
  • Stephan, it works perfect, very professional! Could I ask for some clarifications on it? If I were to run it as line by line in the cmd window, not as a .cmd file, what changes should I make? Besides converting %% in %. The string manipulation is clear but I have no idea what the ! means. Many thanks! – adiv Jan 18 '16 at 22:17
  • +1, Though this will not work properly if any of the lines contain `!` due to expansion of `%%a` while delayed expansion is enabled. This can be fixed with additional code. Also, this will skip lines that begin with `;` due to default EOL value. This can be fixed by using `for /f delims^=^ eol^=` instead of `for /f "tokens=* delims="` – dbenham Jan 18 '16 at 22:28
  • The `!` syntax is for [delayed expansion](http://stackoverflow.com/a/30284028/2152082). I'll add some explanations to the code tomorrow. Making it a one-liner would technically be possible, but it would be creepy. – Stephan Jan 18 '16 at 22:30
1

This is the line:

cmd /V:ON /C "(for /F "delims=" %a in (input.txt) do @set "a=%a" & set "a[!a:~45,7!]=1") & for /F "skip=1 tokens=2 delims=[]=1" %a in ('set a[') do @< NUL >> output.txt set /P "=%a "

Example:

C:\> del output.txt

C:\> cmd /V:ON /C "(for /F "delims=" %a in (input.txt) do @set "a=%a" & set "a[!
a:~45,7!]=1") & for /F "skip=1 tokens=2 delims=[]=1" %a in ('set a[') do @< NUL
>> output.txt set /P "=%a "

C:\> type output.txt
ALNEONO ODUAHRO VBYABYO

EDIT: Another simpler method:

cmd /V:ON /C "set "a= " & (for /F "delims=" %b in (input.txt) do @set "b=%b" & for /F %c in ("!b:~45,7!") do @if "!a:%c=!" equ "!a!" set "a=!a!%c ") & echo !a:~1,-1!> output.txt"
Aacini
  • 65,180
  • 12
  • 72
  • 108
0

Thank you for all your answers I have tried your solutions and they all work. After half a day lost yesterday this is nirvana.

In the end I will try to run all my commands from a .cmd file because sometimes it gets stuck in the for loops. Since I only have access to a terminal I was wondering if there is any way to

  1. open a file, similar to vi in unix?
  2. send all lines (including special characters)
  3. close the file
  4. run it

This is the complete cmd list I have:

@echo off
IF EXIST KHMSC4_DELETE_check.txt del /F KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo             !MSC PRECHECK REPORT STARTS HERE^! >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo !STDEP:DEV=UPDR    --- DELETE PART    ---^! >> KHMSC4_DELETE_check.txt
mml "STDEP:DEV=UPDR-6657&&-6687;" | findstr /I "UPDR" >> KHMSC4_DELETE_check.txt
mml "STDEP:DEV=UPDR-6689&&-6719;" | findstr /I "UPDR" >> KHMSC4_DELETE_check.txt
mml "STDEP:DEV=UPDR-6721&&-6751;" | findstr /I "UPDR" >> KHMSC4_DELETE_check.txt
mml "STDEP:DEV=UPDR-6753&&-6783;" | findstr /I "UPDR" >> KHMSC4_DELETE_check.txt
For /F %%I in ('"type KHMSC4_DELETE_check.txt | findstr /I "BLOC LIBL" | findstr /v "DEVICES" | find /c "UPDR""') Do Set NR_BLOC=%%I

setlocal enabledelayedexpansion
set "output= "
for /F "tokens=* delims=" %%a in (KHMSC4_DELETE_check.txt) do (
  set "string=%%a"
  set "string=!string:~45,7! "
  set "string=!string: =!"
  echo !output!|find "!string!" >nul || set "output=!output:  = ! !string!"
)


echo: >> KHMSC4_DELETE_check.txt
echo ^^!NTCOPP:SNT-RTDMA    --- DELETE PART    ---^^! >> KHMSC4_DELETE_check.txt
echo: >> WINFIOL - DISABLE PAUSE AT EXCHANGE ERRORS FROM OPTIONS -> PREFERENCES -> TRAFFIC SETUP -> PAUSE
mml "NTCOP:SNT=RTDMA-636;" | findstr /I "RTDMA" | findstr /V "NTCOP" >> KHMSC4_DELETE_check.txt
mml "NTCOP:SNT=RTDMA-637;" | findstr /I "RTDMA" | findstr /V "NTCOP" >> KHMSC4_DELETE_check.txt
mml "NTCOP:SNT=RTDMA-638;" | findstr /I "RTDMA" | findstr /V "NTCOP" >> KHMSC4_DELETE_check.txt
mml "NTCOP:SNT=RTDMA-639;" | findstr /I "RTDMA" | findstr /V "NTCOP" >> KHMSC4_DELETE_check.txt


echo: >> KHMSC4_DELETE_check.txt
echo ^^!NUMBER OF DEVICES BLOCKED - DELETE part: %NR_BLOC%. FIRST 5 PRINTED BELOW^^! >> KHMSC4_DELETE_check.txt
type KHMSC4_DELETE_check.txt | findstr /I "BLOC LIBL" | findstr /v "DEVICES" | findstr/n ^^ | findstr "^[0-5]:" >> KHMSC4_DELETE_check.txt"
echo: >> KHMSC4_DELETE_check.txt
echo ^^!LIST OF ROUTES FOR DELETE PART^^! >> KHMSC4_DELETE_check.txt
echo %output:~1% >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo ^^!BLURP AND NUMBER OF DEVICES^^! >> KHMSC4_DELETE_check.txt
mml "BLURP:R=VIUAVIO;" | findstr /v "BLOCKING END" >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
mml "STRSP:R=VIUAVIO;" | findstr /v "DEVICE END" >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txt
echo ^^!MSC PRECHECK REPORT ENDS HERE^^! >> KHMSC4_DELETE_check.txt
echo: >> KHMSC4_DELETE_check.txtecho: >> KHMSC4_DELETE_check.txt
type KHMSC4_DELETE_check.txt
del KHMSC4_DELETE_check.txt

This is how my on-screen report looks because of the exclamation marks

This is how my report looks because of the exclamation marks

Many thanks again for your support!

adiv
  • 46
  • 3
  • `if there is any way to...` Sadly Microsoft has removed `edit` from modern windows. You are supposed to use `notepad.exe`. If you have no access to GUI, you can enter `copy con test.cmd`, then paste the whole code from clipboard and finish the `copy` with ``. (basically, this is "copy from STDIN to file" – Stephan Jan 19 '16 at 15:24
  • Good news, it's Windows 2003 Server. Bad news, i'm connected through an app that does not allow for edit or copy con. Thank you Stephan and all the other who contributed. – adiv Jan 19 '16 at 22:26