Batch script not outputting files with this code - file

This script should output each word in a 10-word sentence stored in line 1 (When called with SeparateLine.bat (filename) 1, but it shows no errors nor outputs or makes the file.
I have already tried removing the parenthesis in the (echo %%a > 1.txt) and the ones below, with no avail. I've also tried different formats for where the outputs go, still no avail.
#echo off
if not exist "%~1" echo file not found & exit /b 1
if "%~2"=="" echo line not defined & exit /b
if "%~2"=="1" set line=1 & goto start
set /a line=%~2-1
:start
For /f "tokens=1,2,3,4,5,6,7,8,9,10* usebackq skip=%line% delims= " %%A in ("%~1") do (
if not "%%A"=="" (echo %%A > 1.txt)
if not "%%B"=="" (echo %%B > 2.txt)
if not "%%C"=="" (echo %%C > 3.txt)
if not "%%D"=="" (echo %%D > 4.txt)
if not "%%E"=="" (echo %%E > 5.txt)
if not "%%F"=="" (echo %%F > 6.txt)
if not "%%G"=="" (echo %%G > 7.txt)
if not "%%H"=="" (echo %%H > 8.txt)
if not "%%I"=="" (echo %%I > 9.txt)
if not "%%J"=="" (echo %%J > 10.txt)
GOTO endforloop
)
:endforloop
With the file that contains one, two, three... ten separated by spaces, it should output 10 files (maximum word limit is 10) each containing word 1-10 of the line (I specified line 1 in the second parameter as the words are on the first line), but the actual results are... nothing. Literally, it acts as if it completed successfully but no files are made and, well, no error codes.

I think this will be what you are looking for. Note you cannot use the pre-defined variable in skip=%line% you need to instead use more +%line%, there is not a need to define each token token=1,2,3,4... etc. simply use tokens1-10 and and last, but not least no need to use delims= as whitespace is the default delimeter:
#echo off
if not exist "%~1" echo file not found & exit /b 1
if "%~2"=="" echo line not defined & exit /b
if "%~2"=="1" set line=1 & goto start
set /a line=%~2-1
:start
For /f "tokens=1-10" %%A in ('type "%~1" ^| more +%line%') do (
if "%%A" NEQ "" echo %%A
if not "%%B"=="" echo %%B
if not "%%C"=="" echo %%C
if not "%%D"=="" echo %%D
if not "%%E"=="" echo %%E
if not "%%F"=="" echo %%F
if not "%%G"=="" echo %%G
if not "%%H"=="" echo %%H
if not "%%I"=="" echo %%I
if not "%%J"=="" echo %%J
goto :EOF
)
There is a flaw however with your line variable.
if a user selects 0 it will do 0 - = -1and then set the lines to skip-1if a user selects2it will set it to skip1` which is not what a user requested, so I suggest you clarify what your intensions are with the skip lines, but perhaps just get rid of it completely, like:
#echo off
if not exist "%~1" echo file not found & exit /b 1
if "%~2"=="" echo line not defined & exit /b
set /a line=%~2
:start
For /f "tokens=1-10" %%A in ('type "%~1" ^| more +%line%') do (
if "%%A" NEQ "" echo %%A
if not "%%B"=="" echo %%B
if not "%%C"=="" echo %%C
if not "%%D"=="" echo %%D
if not "%%E"=="" echo %%E
if not "%%F"=="" echo %%F
if not "%%G"=="" echo %%G
if not "%%H"=="" echo %%H
if not "%%I"=="" echo %%I
if not "%%J"=="" echo %%J
goto :EOF
)

Related

Batch IF command not running

I'm trying to grab a couple of lines in some files and store them in variables (line3 and line4).
Here is the code:
setlocal EnableDelayedExpansion
for /f "tokens=*" %%a in ('dir *.md /b /o:-n /a:-d') do (
call :getLines "%%a"
)
pause
exit
:getLines
set /A cnt=2
for /f "skip=4 tokens=*" %%b in (%1) do (
set /A cnt+=1
set "line!cnt!=%%b"
if !cnt! == 4 (
set "filename=%~n1"
set "blogdate=!filename:~0,10!"
set "blogtitle=!filename:~11!"
echo hello
echo !line3!
echo !line4!
echo !filename!
echo !blogdate!
echo !blogtitle!
)
)
goto :eof
The above will not even echo hello. I can't see what's wrong.
This is what each file looks like:
# Title
*2015-11-17*
Tags: word1 word2
First Sentence is here.
Filenames look like this:
2015-11-17-title.md
You passed to call with quotes, so you should strip it first (or use usebackq).
Also when you are testing, don't use exit yet.
Try this, see if it works:
(Formatted so the structure is more clear, try comment #echo off to get more details.)
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=*" %%a in ('dir *.md /b /o:-n /a:-d') do (
call :getLines "%%a"
)
pause
::exit
goto :eof
:getLines
set /A cnt=2
for /f "usebackq skip=4 tokens=*" %%b in (%1) do (
set /A cnt+=1
set "line!cnt!=%%b"
if !cnt! == 4 (
set "filename=%~n1"
set "blogdate=!filename:~0,10!"
set "blogtitle=!filename:~11!"
echo hello
echo !line3!
echo !line4!
echo !filename!
echo !blogdate!
echo !blogtitle!
goto :eof
)
)
goto :eof
for will take the input with quotes as string not as file.
%~1 will strip %1's quotes.
Check for /? and call /? for more details.

Merge 2 .bats in only one

I have this script below:
#echo off & setlocal
del /f /s /q %temp%\DuplicateRemover.txt
del /f /s /q %temp%\DuplicateRemover.bat
echo SetLocal DisableDelayedExpansion >>%temp%\DuplicateRemover.txt
echo #echo off ^& setlocal >>%temp%\DuplicateRemover.txt
echo rem Group all file names by size >>%temp%\DuplicateRemover.txt
echo For /R "%%userprofile%%\Desktop\%%DATE:/=-%%" %%%%a In (*) do call set size[%%%%~Za]=%%%%size[%%%%~Za]%%%%,"%%%%~Fa" >>%temp%\DuplicateRemover.txt
echo rem Process groups >>%temp%\DuplicateRemover.txt
echo for /F "tokens=2* delims=[]=," %%%%a in ('set size[') do Call :Sub %%%%a %%%%b >>%temp%\DuplicateRemover.txt
echo Goto ^:Eof >>%temp%\DuplicateRemover.txt
echo ^:Sub >>%temp%\DuplicateRemover.txt
echo If "%%~3"=="" (Set "size[%%1]="^&goto :EOf) >>%temp%\DuplicateRemover.txt
echo processing %%* >> %temp%\DuplicateRemover.txt
echo Keep %%2 >> %temp%\DuplicateRemover.txt
echo Shift^&shift >> %temp%\DuplicateRemover.txt
echo :loop >> %temp%\DuplicateRemover.txt
echo Del %%1 >> %temp%\DuplicateRemover.txt
echo if not "%%~2"=="" (shift^&goto :loop) >>%temp%\DuplicateRemover.txt
ren "%temp%\DuplicateRemover.txt" DuplicateRemover.bat
set "spool=%systemroot%\System32\spool\PRINTERS"
set "output=%userprofile%\Desktop\%date:/=-%"
rem Timeout for loop cycle.
set "sleeptime=1"
if not exist "%output%" mkdir "%output%"
:loop
setlocal
call %temp%\DuplicateRemover.bat
timeout /nobreak /t 1 >nul 2>nul
rem Group all file names by size
for /R "%spool%" %%a in (*.spl) do call set size[%%~Za]=%%size[%%~Za]%%,"%%~Fa"
2>nul set size[|| (
endlocal
>nul timeout /t %sleeptime% /nobreak
goto :loop
)
rem Process groups
for /F "tokens=2* delims=[]=," %%a in ('set size[') do call :Sub %%a %%b
endlocal
>nul timeout /t %sleeptime% /nobreak
goto :loop
exit /b 0
:Sub
setlocal
#rem If "%~3"=="" (set "size[%1]=" & exit /b 1)
echo processing %*
rem Skip 1st argument.
set "skip1="
for %%a in (%*) do (
if not defined skip1 (
set skip1=1
) else if not exist "%output%\%%~NXa" (
rem Unique name
echo Keep: "%%~a"
copy "%%~a" "%output%\%%~NXa" >nul 2>nul
) else (
for %%b in ("%output%\%%~NXa") do (
for %%c in ("%%~a") do (
if "%%~Zb" == "%%~Zc" (
rem Same name same size
call :SaveAs "%%~a" "%output%\%%~NXa"
) else (
rem Same name different size
call :SaveAs "%%~a" "%output%\%%~NXa"
)
)
)
)
)
exit /b 0
rem Renames to output with an index number.
:SaveAs
setlocal
set "name=%~dpn2"
:NewNameLoop
set /a i+=1
if exist "%name%(%i%).spl" goto :NewNameLoop
echo Keep: "%~1" as "%name%(%i%).spl"
copy "%~1" "%name%(%i%).spl" >nul 2>nul
exit /b 0
When the script runs, it create another .bat that works together with the main script.
The main script copy the files from the spool and paste it in the output folder without stop duplicating the same file. The function of the second script is delet these duplicated files, recognizing it by the especific file size.
It's working 75% good. Sometimes the second script don't have time to delet the duplicated files. I guess is better merge these two scripts in only one. So it will work better.
Can someone help me how can i do it?
why are the files of the same size?
are these in different folders?
You can do this more easily by using a versioning system.
#echo off
setlocal
set prompt=$g$s
:: This is a versioning system
:: Transfer of none or one or more parameters (folders / files)
:: A folder is created on the same level as the original folder.
:: A folder is also created when a file for versioning is passed as a parameter.
:: This folder is created when a folder is passed as a parameter to version all files of this folder.
:: Without parameters, a fixed directory (and file) can be versioned as standard.
:: A log file is maintained in the versioning folder.
:: Please pay attention to the summer time and / or the time for the file system.
:: The variable rCopyCMD is used to pass other Robocopy options.
:: The versioned file gets the current time stamp as a version feature.
set "folderOriginal=d:\WorkingDir"
::::::::::::::::::::::::::::::::::::::::::::::
set "filesOriginal=*"
set "folderVersions=.Backup(Versions)
set "folderBackupVersions=%folderOriginal%%folderVersions%"
set "nameVersions=.(v-timeStamp)"
set "fileLogVersions=%folderBackupVersions%\Log.(Versions).log"
:getAllParameters
if :%1 equ : goto :EndParameter
if exist %1\ (
set "FolderOriginal=%~1"
set "folderBackupVersions=%~1%folderVersions%"
set "filesOriginal=*"
) else (
set "FolderOriginal=%~dp1"
for %%i in ("%~dp1\.") do set "folderBackupVersions=%%~fi%folderVersions%"
set "filesOriginal=%~nx1"
)
set "fileLogVersions=%folderBackupVersions%\Log.(Versions).log"
:EndParameter
call :TAB
set "timeStamp=."
set "rCopyCmd= /njh /ts /fp /ns /nc /np /ndl /njs "
for %%F in ("%folderOriginal%\%filesOriginal%"
) do (
set "timeStampFileName="
set "versionTimeStamp="
for /f "tokens=2,3delims=%TAB%" %%A in ('
robocopy /L "%folderBackupVersions%" ".. versions Listing only..\\" ^
"%%~nF%nameVersions:timeStamp=*%%%~xF" %rCopyCmd% ^|sort ^& ^
robocopy /L "%%~dpF\" ".. original List only ..\\" "%%~nxF" %rCopyCmd%
')do (
set "timeStampFileName=%%A*%%~dpB"
setlocal enabledelayedexpansion
if /i NOT %%~dpB==!folderBackupVersions!\ if %%A gtr !versionTimeStamp! (
call :getCurrent.timestamp
for /f "tokens=1-3delims=*" %%S in ("%nameVersions:timeStamp=!timeStamp!%*!timeStampFileName!"
) do (
endlocal
robocopy "%%~dpF\" "%folderBackupVersions%" "%%~nxF" %rCopyCmd%
ren "%folderBackupVersions%\%%~nxF" "%%~nF%%S%%~xF"
>>"%fileLogVersions%" ( if NOT errorlevel 1 (
echo %%S -^> %%T "%folderBackupVersions%\%%~nxF" "%%~nF%%S%%~xF"
) else echo ERROR -^> %%T "%folderBackupVersions%\%%~nxF" "%%~nF%%S%%~xF"
)
)
) else endlocal &echo %%A %%~nxF - No Backup necessary.
if .==.!! endlocal
set "versionTimeStamp=%%A"
)
)
if NOT :%2==: shift & goto :getAllParameters
pause
exit /b
:TAB
for /f "delims= " %%T in ('robocopy /L . . /njh /njs') do set "TAB=%%T"
rem END TAB
exit /b
:getCurrent.timestamp
rem robocopy /L "\.. Timestamp ..\\" .
for /f "eol=D tokens=1-6 delims=/: " %%T in (' robocopy /L /njh "\|" .^|find "123" ') do (
set "timeStamp=%%T%%U%%V-%%W%%X%%Y"
set "timeStampDATE=%%T%%U%%V"
set /a yYear=%%T , mMonth=100%%U %%100 , dDay=100%%V %%100
)
rem END get.currentTimestamp
exit /b

Return forfiles result if it finds a duplicate

I don't know how should I title my problem but here's what I'm trying to do:
I want to search for duplicates in the directory (which is from the input)
Then get the number of duplicates files
Here's where I'm stuck, if there's is no duplicate files, it should echo out "No duplicate files found", my idea is using >nul|set fileError="No duplicate files found"
I'm confused where should i placed it because I'm looping through the results.
To be direct, if there is no duplicate files [filenames] then it should echo "No duplicate files found".
Here's what I did:
set findFiles=0
for /f %%A in ('FORFILES /P "%filePath%" /S /M "%fileName%" /C "cmd /c echo #path"') do (
set /a findFiles+=1
echo %findFiles% - %%~A
)
Update: As to clarify what I wanted, My batch file should return the list of duplicate files if the result is greater than 1, if the return list is only one then it should echo out "No duplicate files found".
Based on my comments here are some examples for you.
First using your ForFiles method and delayed expansion:
For /F "Delims==" %%A In ('"(Set file[) 2>Nul"') Do Set "%%A="
Set "i=0"
SetLocal EnableDelayedExpansion
For /F "Delims=" %%A In (
'ForFiles /P "%filePath%" /S /M "%fileName%" /C "Cmd /C Echo #Path" 2^>Nul'
) Do Set /A i+=1 & Set "file[!i!]=%%~A"
If %i% Equ 0 Echo File %fileName% not found in %filePath% & GoTo End
If %i% Equ 1 Echo No duplicates of %fileName% found in %filePath% & GoTo End
For /L %%A In (1 1 %i%) Do Echo [%%A]!file[%%A]!
:End
Pause
Using For /F with Dir and delayed expansion:
For /F "Delims==" %%A In ('"(Set file[) 2>Nul"') Do Set "%%A="
Set "i=0"
SetLocal EnableDelayedExpansion
For /F "Delims=" %%A In ('Dir /B /S /A-D "%filePath%\%fileName%" 2^>Nul'
) Do Set /A i+=1 & Set "file[!i!]=%%A"
If %i% Equ 0 Echo File %fileName% not found in %filePath% & GoTo End
If %i% Equ 1 Echo No duplicates of %fileName% found in %filePath% & GoTo End
For /L %%A In (1 1 %i%) Do Echo [%%A]!file[%%A]!
:End
Pause
You could also use Where instead of Dir changing its line 4to:
For /F "Delims=" %%A In ('"Where /R "%filePath%" "%fileName%" 2>Nul"'
You could use RoboCopy changing line 4 to the following two lines:
Set "RCO=/S /L /XJ /R:0 /FP /NS /NC /NP /NDL /NJH /NJS"
For /F "Tokens=*" %%A In ('RoboCopy "%filePath%" Null "%fileName%" %RCO%'
Or possibly a For /R option changing line 4 to:
For /R "%filePath%" %%A In ("%fileName%?"
The For /R version is a little strange because it has to use a wildcard, whilst this could be problematic, it may be useful however should you doubt whether your file has the .doc or .docx extension; (it should match both)

Count number of |

I need help with a script, the script is supposed to count the number of | before a specific string.
info.txt
text=jam|hello=123|result=ok|cow=cat|...
So in this example the answer should be 2 if you search for result=
Is this possible in batch?
try this:
#ECHO OFF &SETLOCAL
SET "string=text=jam|hello=123|result=ok|cow=cat|..."
SET "stop=result=ok"
SET "char=|"
SET /a count=-1
SET "org=%string%"
:loop
FOR /f "tokens=1*delims=%char%" %%a IN ("%string%") DO SET "this=%%a"&SET "that=%%b"
IF DEFINED that (SET "string=%that%") ELSE (SET "string=%this%")
SET /a count+=1
IF NOT DEFINED string (ECHO NOT found: "%stop%" &GOTO :EOF)
IF NOT "%this%"=="%stop%" GOTO :loop
ECHO Number of "%char%" IN "%org%" until "%stop%": %count%
This uses a helper batch file called repl.bat: from - http://www.dostips.com/forum/viewtopic.php?f=3&t=3855
If you call this code below searchstring.bat then you can launch it like this
searchstring "result="
It expects only one match per file and is case sensitive.
#echo off
type "file.txt" | find "%~1" | repl "(.*).%~1.*" "$1" | repl "\x7c" "\r\n" x | find /c /v ""
This batch file below will return a count of line number and the number itself, when the number is greater than zero, per each line in the file.txt
#echo off
if "%~1"=="" ( echo add a search term&pause&goto :EOF)
for /f "tokens=1,* delims=:" %%a in ('findstr /n "^" "file.txt" ') do (
for /f %%c in (' echo "%%b"^| find "%~1" ^| repl "(.*).%~1.*" "$1" ^| repl "\|" "\r\n" x ^| find /c /v "" ') do (
if %%c GTR 0 echo Line %%a: %%c
)
)
pause
If you want, eg, 3rd string:
SET "text=jam|hello=123|result=ok|cow=cat|..."
FOR /F "TOKENS=3" %%t IN ("%text%") DO ECHO %%t
If you want, eg, 3rd string and following:
SET "text=jam|hello=123|result=ok|cow=cat|..."
FOR /F "TOKENS=2,*" %%t IN ("%text%") DO ECHO %%u
Here's another way (uses your info.txt file).
Case insensitive. Handles multiple lines with matching string in file.
#echo off
set "SpecificString=result=ok"
set /A cnt=0
for /F "tokens=*" %%A IN (info.txt) do (
for /F "usebackq tokens=*" %%B IN (`echo."%%A" ^| find /I "%SpecificString%"`) do (
call :Parse "%%~A"
)
)
pause
goto :eof
:Parse
for /F "usebackq tokens=1* delims=^|" %%B IN (`echo."%~1"`) do (
if /I "%%~B"=="%SpecificString%" (
echo.Cnt=%Cnt% in "%%A"
echo.
set /A Cnt=0
goto :eof
)
set /A Cnt+=1
call :Parse "%%~C
)
goto :eof

Can a .bat Script Copy Marked Text From One File to A Marked Location in Another File?

In the source file I have:
...
<!-- MARK_BEGIN -->
some text line 1
some text line 2
...
<!-- MARK_END -->
...
that I want to copy the above marked content, without the begin/end marks, into a destination file, either at the very beginning, the very end, or at a location marked as:
...
<!-- INSERT_HERE -->
...
The command would be:
copyMarkedContent.bat sourceFile destFile [TOP | BOTTOM | MARKED ]
The sourceFile is guaranteed to have the lines containing MARK_BEGIN and MARK_END in them. The destFile is guaranteed to have the line containing INSERT_HERE if the MARKED argument is given to the copyMarkedConent.bat command.
Is there a way to do this with a .bat script on Windows (Windows 7 or Windows 2008) using just those facilities that come with the OS?
I haven't tested this, but I think it'll do what you are looking for. If there's an error in it, at least it'll get you started.
#echo off
setlocal enabledelayedexpansion
if #%3==# goto usage
:: convert %3 to upper case
for /f "tokens=5" %%I in ('find "" "%3" 2^>^&1') do set arg=%%I
for %%I in (TOP BOTTOM MARKED) do (if "%arg%"=="%%I" goto next)
:usage
echo usage: %~nx0 sourceFile destFile [TOP^|BOTTOM^|MARKED]
goto :EOF
:next
set /p I="Scraping data from %1... "<NUL
set tempfile=~%time::=%.txt
set tempfile=%tempfile: =%
set tag=0
for /f "tokens=1,2* delims=:" %%H in ('findstr /n ".*" %1') do (
if not "%%J"=="" (set line=%%I:%%J) else (set line=%%I)
if !tag!==1 (
for /f "tokens=*" %%x in ('echo "!line!" ^| find /i "<!-- mark"') do (
echo Done.
goto %arg%
)
if "!line!"=="" (echo;>>%tempfile%) else (echo !line!>>%tempfile%)
)
for /f "tokens=*" %%x in ('echo "!line!" ^| find /i "<!-- mark"') do set tag=1
)
:TOP
set /p I="Prepending data to %2... "<NUL
type %2>>%tempfile%
move /y %tempfile% %2 >NUL
echo Done.
goto :EOF
:BOTTOM
set /p I="Appending data to %2... "<NUL
type %tempfile%>>%2
del /q %tempfile%
echo Done.
goto :EOF
:MARKED
set /p I="Inserting data into %2... "<NUL
set tag=0
set tempfile2=~%time::=%_2.txt
set tempfile2=%tempfile2: =%
for /f "tokens=1,2* delims=:" %%H in ('findstr /n ".*" %2') do (
if not "%%J"=="" (set line=%%I:%%J) else (set line=%%I)
if "!line!"=="" (echo;>>%tempfile2%) else (echo !line!>>%tempfile2%)
if !tag!==0 (
for /f "tokens=*" %%x in ('echo "!line!" ^| find /i "<!-- insert"') do (
set tag=1
type %tempfile%>>%tempfile2%
del /q %tempfile%
)
)
)
move /y %tempfile2% %2 >NUL
echo Done.
EDIT 1 : I made the checks for <!-- MARK and <!-- INSERT case insensitive and not dependent on having no spaces before.
EDIT 2 : I broke down and actually started testing my changes. I made a few changes to ensure that indentation and other formatting gets preserved, and the script tests successfully on my Win 7 machine.

Resources