Thursday, May 5, 2011

Batch File - Into a Variable

Hi guys Havin' problems tryin' to get the string after the : in the following two lines into two seperate variables from the bottom of a text file called file.txt for example

Number of files to delete:  27 Total
Total size of files to delete: 1,427 KB

I just want the 27 in one variable, and the 1,427 in another. These are randomly generated from a scan, and could include more digits. Hope you understand :)

Thanks for yall your help

Batch file please, i am using windows

From stackoverflow
  • I assume You need this to be done in pure bash.

    #!/bin/bash
    S="$(<testfile.txt)" # load the data
    
    A="${S#*:}" # remove everything before the first : (including it)
    A="${A%%Total*}" # remove everything after the first "Total" (including it)
    
    B="${S##*:}" # remove everything before the last : (including it)
    B="${B% *}" # remove everything after the last space (including it)
    
    A="${A// }" # remove all spaces
    B="${B// }"
    
    echo "-$A-" # print results (showing that there are no spaces in it)
    echo "-$B-"
    

    I encourage You to explore Parameter Expansion section of man bash. You will find numerous usefull tricks there.

    Reef : I've ran some tests, this script (with `echo` removed) executes 3500times/s on my box, 22000 times/s when loading the file is done only once. Looking forward for other solutions with head, tail, cut and cat ;)
    Andy : This looks like an excellent bash answer, but I think he might be on Windows. See batch and cmd tags
  • I am using Windows, and would prefer it to be purely in cmd :)

  • Something like this should work:

    @echo off
    setlocal enableextensions enabledelayedexpansion
    
    :: Get the number of lines in the file
    set LINES=0
    for /f "delims==" %%I in (file.txt) do (
        set /a LINES=LINES+1
    )
    
    :: Parse the last 2 lines and get the numbers into variable NUMS
    set /a LINES=LINES-2
    for /f "skip=%LINES% delims=" %%L in (file.txt) do (
        for /f "tokens=1-2* delims=:" %%A in ("%%L") do (
            for /f "tokens=1-2*" %%N in ("%%B") do set NUMS=!NUMS!%%N;
        )
    
    )
    
    :: Parse variable NUMS
    for /f "tokens=1-2* delims=;" %%A in ("%NUMS%") do (
        set NUM_FILES=%%A
        set TOTAL_SIZE=%%B
    )
    
    @echo Number of files     = %NUM_FILES%
    @echo Total size of files = %TOTAL_SIZE%
    
  • I dont have enough rep to comment so i will have to post it into an answer. Thankyou for your contributions there mate, but unfortunately im unable to test, as I'm gettin' this error here when running the batch script. I've uploaded a screenshot. I copied and pasted your code directly, and only edited the filename portion.

    http://tinypic.com/view.php?pic=2powpsp&s=5

    Patrick Cuff : What flavor of Windows are you using? How are you getting a command prompt, via cmd.exe or command.com?
    Patrick Cuff : From your screen shot it also looks like there's some unprintable character before the '@'; that may be throwing things off.
  • @Patrick Cuff

    An update.. It is not your script that is the problem. I tried a batch file with just @echo off in it and ran it and I get the same error; so I know its not your script that it is doing it. Further more; I have no clue to why it is doing this? Maybe you've come across somethin' similar before?

    I haven't done much batch scripting before and have never seen this. I have piped the set command to a txt file and copied and pasted it below. It doesn't seem like anythin' has changed to me.

    ALLUSERSPROFILE=C:\ProgramData
    APPDATA=C:\Users\Methical\AppData\Roaming
    CLASSPATH=.;C:\Program Files\Java\jre6\lib\ext\QTJava.zip
    CommonProgramFiles=C:\Program Files\Common Files
    COMPUTERNAME=NEMESIS
    ComSpec=C:\Windows\system32\cmd.exe
    DFSTRACINGON=FALSE
    FP_NO_HOST_CHECK=NO
    HOMEDRIVE=C:
    HOMEPATH=\Users\Methical
    LOCALAPPDATA=C:\Users\Methical\AppData\Local
    LOGONSERVER=\\NEMESIS
    NUMBER_OF_PROCESSORS=1
    OS=Windows_NT
    Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files\QuickTime\QTSystem\
    PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    PROCESSOR_ARCHITECTURE=x86
    PROCESSOR_IDENTIFIER=x86 Family 6 Model 15 Stepping 13, GenuineIntel
    PROCESSOR_LEVEL=6
    PROCESSOR_REVISION=0f0d
    ProgramData=C:\ProgramData
    ProgramFiles=C:\Program Files
    PROMPT=$P$G
    PUBLIC=C:\Users\Public
    QTJAVA=C:\Program Files\Java\jre6\lib\ext\QTJava.zip
    SystemDrive=C:
    SystemRoot=C:\Windows
    TEMP=C:\Users\Methical\AppData\Local\Temp
    TMP=C:\Users\Methical\AppData\Local\Temp
    TRACE_FORMAT_SEARCH_PATH=\\NTREL202.ntdev.corp.microsoft.com\4F18C3A5-CA09-4DBD-B6FC-219FDD4C6BE0\TraceFormat
    USERDOMAIN=Nemesis
    USERNAME=Methical
    USERPROFILE=C:\Users\Methical
    windir=C:\Windows
    
    Patrick Cuff : That looks OK. Are you using a localized version of Vista (non-US)? Just for laughs, change the extension of the script from .bat to .cmd and see what that does. Do any .bat scripts work for you?
  • @Patrick Cuff

    I realised that I had been always editing the same batch file. So I deleted it. Started a new one from scratch thru notepad, saved it as a .bat and ran it. No errors this time. So I copied and pasted your code into a new batch file, and ran it.

    Well.. It ran, but there was an error. Havin' problems embedding the picture; but heres the link.

    screenshot

    Patrick Cuff : @jimbob15; change `@echo OFF` to `@echo ON` and see where the error is occurring. I can run this on XP and Server 2003 with no problems.
  • @Patrick Cuff I am running Windows Vista Home Basic SP1. I would like it compatible for Vista and XP if possible.

    I changed the echo off to on, and ive uploaded another screenshot for u. And also the relevant text file that im tryin' to extract the values from.

    clean.txt

    Screenshot2

    Patrick Cuff : The output for the first `for` command should be "D:\>for /F "skip=280 delims=" %L in (clean.txt) do (for /F "tokens=1-2* delims=:" %A in ("%L") do (for /F "tokens=1-2*" %N in ("%B") do set NUMS=!NUMS!%N; ) )". It looks like the LINES var is not being set. Try changing `delims==` to `delims=`.
    Patrick Cuff : @jimbob15; the 280 lines is for the clean.txt file you provided and is computed for whatever file you specify. If you have a file with 10,000 lines this value should be 10,000. It's not hard coded in the script. When you turn `@echo ON` the command output is printed to the console window. From your output it looked like the `for` command output was missing the value of the `LINES` variable, which is probably where the problem is.
    Patrick Cuff : My guess is that the script can't find the file 'clean.txt'; where does it reside? Try specifying the full path rather than just the file name.
    Patrick Cuff : In the first `for` command do you have `set /a LINES=LINES+1` or `set /a LINES=%LINES%+1`? You should have the first one. When I change my script to the second I get the errors your seeing.
    Jay : Within **for loops**, try the following incrementation style: set /a var+=1. With this, you don't need to re-read the variable content thus don't need the setlocal.
  • This is my full batch file;

    @echo on
    setlocal enableextensions enabledelayedexpansion
    
    :: Get the number of lines in the file
    set LINES=0
    for /f "delims==" %%I in (D:\clean.txt) do (
        set /a LINES=LINES+1
        echo %LINES%
    )
    
    :: Parse the last 2 lines and get the numbers into variable NUMS
    set /a LINES=LINES-2
    echo %LINES%
    for /f "skip=%LINES% delims=" %%L in (D:\clean.txt) do (
        for /f "tokens=1-2* delims=:" %%A in ("%%L") do (
            for /f "tokens=1-2*" %%N in ("%%B") do set NUMS=!NUMS!%%N;
        )
    
    )
    
    :: Parse variable NUMS
    for /f "tokens=1-2* delims=;" %%A in ("%NUMS%") do (
        set NUM_FILES=%%A
        set TOTAL_SIZE=%%B
    )
    
    @echo Number of files     = %NUM_FILES%
    @echo Total size of files = %TOTAL_SIZE%
    

    You can see where i put the extra echoes in, too see the value of the variable and i get the previous screenshot. Why does it work for you and not me? thats not fair lol I'm running Vista Home Basic SP1 32-bit

    Patrick Cuff : The `echo %LINES%` inside the `for` loop are evaluated before the `for` command is executed, so will always display zero. To see if `LINES` is being incremented use delayed expansion; `echo !LINES!`. Other than that, your script works for me. I don't have access to a Vista system, but I will run this on Windows 7 and see what happens.
    Patrick Cuff : Both scrips work for me on Windows 7. See my newest answer for a different possible solution.
  • It looks like you're having some problem with reading through the whole file to get the number of lines. This solution will find just the strings you're interested in and get the values:

    @echo off
    setlocal enableextensions enabledelayedexpansion
    
    :: Get number of files to delete.
    for /f "usebackq tokens=1-7" %%A in (`findstr /b "Number of files to delete:" file.txt`) do (
        set NUM_FILES=%%F
    )
    
    :: Get total size of files.
    for /f "usebackq tokens=1-8" %%A in (`findstr /b "Total size of files to delete:" file.txt`) do (
        set TOTAL_SIZE=%%G
    )
    
    @echo Number of files     = %NUM_FILES%
    @echo Total size of files = %TOTAL_SIZE%
    

    If the strings with the number of files and total size ever change, you'll have to change the script accordingly.

  • Sorry for another answer, but I can comment sometimes, but othertimes not. Or maybe i can only comment to my own answers...

    Anyway, ran your latest script, still no variables appear.. I have asked on another forum for an answer for this to, but still havin' no luck there.. Here is an answer I got in a reply to an email from someone I asked to help me..

    Salve (Hi) Tim, sorry you had to wait for my response, but other than the time-lag I faced a strange issue with your text file. What I discovered explains the weird behavior you reported while running my original script. Your text file is encoded in Unicode-like format but missing the 0xFF-0xFE marker in the first two bytes. That prevents Windows correctly processes its content. The same happened when you saved my batch code. Notepad gives you a broad chance to open the file even if it is not correctly encoded, but in console window the rules are more strict.
    When you save a text file ensure to save in Unicode or (better) ANSI format. I don't know how you generated such a format that, I repeat, doesn't belong to standard Windows' formats.

  • jimbob, here is what I came up with:

    delfiles.cmd

    @echo off
    set file=clean.txt
    call :grep "Number of files to delete:"
    set files=%grep%
    call :grep "Total size of files to delete:"
    set size=%grep%
    
    echo %Files% files of a total size of %size% are to be deleted.
    exit /b 0
    
    :grep
        setlocal
        for /F "tokens=2 delims=:" %%i in ('findstr /i /c:"%~1" "%file%"') do (
          for /F "tokens=1 delims= " %%j in ("%%i") do set _find=%%j
        )
        endlocal& set grep=%_find%
        exit /b 0
    

    This is a re-usable script, as the file and strings can be changed with the same results. I copied/pasted your example and it worked good.

    @Patrick Cuff: you might run into problems finding a whole string without the /c:".." part. Might have been a part of the problem, but then maybe my script will give the same results/problems... Live and learn I guess.

    ______Notes__________
    set file= : Set this to the file (and path, if needed) of the file to be scanned.
    call :grep "string" : Call the :grep function with the string to find.
    set var=%grep% : Set a variable (here files and size) to the answer from :grep.

    :grep function: It first looks within the %file% for the "%string%", then parse it at the ':' character, keeping the right-hand part. It then parse it again with 'spaces' and keep the first word. The function returns the variable %grep% which contain the found string.

    As with my usual answers, I hope this helps.

0 comments:

Post a Comment