I want to search all files in a certain directory and print results in text file.
But i want results in separated by '|' based on file name.
Example.
My Input files are
A.txt and B.txt etc...
My Batch Script
#echo off
setlocal
pushd D:\Source
findstr /c:"Apple" /c:"Banana" /c:"Grapes" *.txt > Results.txt
popd
endlocal
Results are coming like this
a.txt Apple
a.txt Banana
b.txt Banana
b.txt Grapes
But i want result like this
a.txt Apple|Banana
b.txt Banana|Grapes
HOW TO GET HELP!!
#ECHO OFF
SETLOCAL enabledelayedexpansion
SET "sourcedir=c:\sourcedir\abg"
SET "resultfile=results.xtx"
pushd %sourcedir%
DEL %resultfile% 2>nul
SET "filename="
FOR /f "tokens=1*delims=:" %%r IN ('findstr "Apple Banana Grapes" *.txt') do (
IF "!filename!"=="%%r" (
SET "line=!line!|%%s"
) ELSE (
IF DEFINED filename >>%resultfile% ECHO(!filename! !line!
SET "filename=%%r"
SET "line=%%s"
)
)
IF DEFINED filename >>%resultfile% ECHO(!filename! !line!
TYPE %resultfile%
popd
GOTO :EOF
I set up the destination filename as a variable in order to avoid the problem that the results.txt file may be included in the input processing, since it is created in the same directory as the data files.
I also changed the directory name to suit my system.
#echo off
setlocal EnableDelayedExpansion
cd D:\Source
set "filename="
for /F "tokens=1* delims=:" %%a in (
'findstr "Apple Banana Grapes" *.txt') do (
if not defined filename (
set /P "=%%a %%b" < NUL
set "filename=%%a"
) else if "!filename!" equ "%%a" (
set /P "=|%%b"
) else (
echo/
set /P "=%%a %%b" < NUL
set "filename=%%a"
)
)
echo/
Some notes on previous code:
endlocal command at end is not necessary.
pushd command and a popd at end may be replaced by setlocal followed by cd at beginning and nothing at end.
In findstr command you may define several strings to search separating they with space.
Related
I am completely new to .bat code. I want to merge two csv file based on common column and selective columns for the output file.
For ex
file1.csv
id,name,roll
1,x,12
2,y,13
file2.csv
id,class,subject
1,V,english
2,III,Math
Output will be
result.csv
id,name,class,subject
1,x,V,english
2,y,III,Math
Below is the code I started. My problem is how to use the common column and select the column.
#echo off
set "tmpfile=%temp%\result.tmp"
set "csvfile=result.csv"
copy nul "%tmpfile%" >nul
echo.
echo Processing all CSV files...
set "header="
for %%a in (%1) do (
if not "%%a"=="%csvfile%" (
set /p =Processing %%a...<nul
for /f "tokens=1* usebackq delims=," %%b in ("%%a") do (
if /i "%%b"=="Keyword" (
if not defined header (
set /p =Found header...<nul
set "header=%%b,%%c"
)
) else (
title [%%a] - %%b,%%c
findstr /b /c:"%%b" /i "%tmpfile%">nul || echo %%b,%%c>>"%tmpfile%"
)
)
echo OK
)
)
echo Finished processing all CSV files
echo.
echo Creating %csvfile%
echo %header%>"%csvfile%"
set /p =Sorting data...<nul
sort "%tmpfile%">>"%csvfile%"
echo OK
del "%tmpfile%"
echo Finished!
title Command Prompt
exit /b
The problem description lacks multiple details and the example code provided has no relation to the description. In the description you talk about two files but in the code you process "all CVS files" with no indication of which "two files" should be merged. The code has an undescribed "Keyword" value. The code sorts the output file, but this is not necessary because "both input files are sorted by common column" as you said...
Anyway I tried to help you writting a working code that achieve what you said in the problem description. I searched for "file merge" in the Batch-file tag and get multiple results, so I just used this method as base...
#echo off
setlocal EnableDelayedExpansion
set "Header1="
set "Header2="
set "common2=-999999999"
rem Read second file from redirected input
< file2.csv (
rem Read first file via FOR /F
for /F "tokens=1,2 delims=," %%a in (file1.csv) do (
if not defined Header1 (
set "Header1=%%a,%%b"
) else (
if !common2! lss %%a call :ReadNextFile2RecordUntil %%a
if !common2! equ %%a echo %%a,%%b,!rest2!
)
)
) > result.csv
goto :EOF
:ReadNextFile2RecordUntil commonCol
set "line2="
set /P "line2="
if not defined line2 set "common2=999999999" & exit /B
for /F "tokens=1* delims=," %%A in ("%line2%") do (
if not defined Header2 (
set "Header2=%%B"
echo %Header1%,%%B
goto ReadNextFile2RecordUntil %1
) else (
set "common2=%%A"
set "rest2=%%B"
)
)
if !common2! lss %1 goto ReadNextFile2RecordUntil %1
exit /B
file1:
id,name,roll
1,x,12
2,y,13
4,z,record1 with no matching record2
5,t,15
file2.csv:
id,class,subject
1,V,english
2,III,Math
3,IV,record2 with no matching record1
5,V,OK
result.csv:
id,name,class,subject
1,x,V,english
2,y,III,Math
5,t,V,OK
So I need a code that will take a text file (we'll cal it list.txt) and turn every line into a variable.
To give some context, I have some file names listed in list.txt, which adds and deletes file names occasionally by user request. I want the user of this code to be able to select which document they'd like to open using variables.
For example, if list.txt looks like this
list.txt
loading.txt
test1.txt
test2.txt
test3.txt
test4.txt
Then I'd like an automatic variable for every .txt listed. I then would add a simple if statement to open the file matched with the variable.
Am I making this too complicated for myself or is this the only way to do this?
EDIT:
I am not attempting something like this:
type list.txt
echo.
echo.
set /p GROUPSELECT= Please type out the FULL name of the group listed:
CD %grouplist%
type %GROUPSELECT%
It will display the file contents, and then display the specific file chosen by the input. I'd think that the variable might be easier to do more with later though, just a thought.
Edit2
I tried this:
#Echo OFF
FOR /F "Usebackq Delims=" %%a IN (
"list.txt"
) DO (
set jim=%%a
)
echo %jim%
PAUSE
%jim% will only be the last line in the text file, so how do I make the next step into making them all different?
Give this a try. I have commented each line of code that should explain what it is doing. Let me know if you need any further explanation.
#echo off
REM FOR commnd is parsing the output of the FINDSTR commands.
REM First FINDSTR command is finding non empty lines in the file
REM Second Findstr command is assigning a number to each line of the file
REM The output is split into two tokens and the number is assigned to %%G and the line of the file to %%H
for /F "tokens=1* delims=:" %%G IN ('findstr /V "^$" list.txt ^|findstr /N ".*"') DO (
REM create a variable of the lines in the file
set "file%%G=%%H"
REM Create a menu of the lines in the file
echo %%G %%H
REM Get the number of lines in the output
set "num=%%G"
)
REM Ask user to chose a number
set /P "filenum=Chose a file number 1 to %num%:"
REM Need to enable delayed expansion to use array variables
setlocal enabledelayedexpansion
REM Check if they type in a correct number and display the file
IF DEFINED file%filenum% type !file%filenum%!
endlocal
pause
Is this the sort of thing you're looking for?
#For /F "Delims==" %%# In ('Set # 2^>Nul')Do #Set "%%#="
#For /F Tokens^=1*Delims^=[]^ EOL^= %%# In ('Type "file.txt"^|Find /V /N ""'
)Do #Set "#%%#=%%$"&Echo( %%#. %%$
:Opt
#Echo(
#Set /P "Opt=Choose a document to open>"
#Set #|Findstr /B "#%Opt%=">Nul||GoTo :Opt
#Call Start "" "%%#%Opt%%%"
Just change the name of the text file containing your list on line 2 as needed.
#TheBoy your question is confusingly framed. If you DO NOT want the example you put in the edit, then can you better explain what you DO want??
Do you want to say iterate over the list file, and create a choice screen?
#(SETLOCAL EnableDelayedExpansion
ECHO OFF
SET "_ChoiceList_File=C:\Admin\ChoiceFile.txt"
REM Full Character List to populate Choices
SET "_CharList=0 1 2 3 4 5 6 7 8 9 A B C D E F N X"
)
CALL :Main
( ENDLOCAL
EXIT /B 0
)
:Main
REM Now we can Do Our Choices btu lets do it in a Sub Function.
CALL :MakeChoice _ChoiceResult
ECHO.
ECHO The Index Chosen Was: %_Chosen%
ECHO The Result Matched is: "%_ChoiceResult%"
REM ECHO Here you output "%_ChoiceResult%"
TYPE "%_ChoiceResult%"
GOTO :EOF
:MakeChoice
cls
color 1A
SET %~1="
SET "_Choices="
SET "_Chosen="
SET "_Amount="
SET "_Choice.17.Value=Next Set!"
SET "_Choice.18.Value=EXIT!"
SET "_Choice_Show_Next="
echo. Pick a File:
echo.========================
REM Create Numbered Array of Choices and output Choices to the Screen
FOR /F "tokens=* usebackq" %%A IN ("%_ChoiceList_File%") DO (
SET /A "_Amount+=1"
SET "_Choice.!_Amount!.Value=%%A"
IF !_Amount! EQU 16 (
SET /A "_Amount+=2"
CALL :MakeChoice "%~1"
IF DEFINED _Chosen (
IF !_Chosen! NEQ 17 (
REM IF !_Chosen! NEQ 18 (
GOTO :EOF
REM )
)
SET "_Amount="
SET "_Chosen="
)
)
)
IF NOT DEFINED _Chosen (
SET /A "_Amount+=1"
SET "_Choice.!_Amount!.Value=!"
SET /A "_Amount+=1"
SET "_Choice.!_Amount!.Value=EXIT!"
CALL :MakeChoice "%~1"
)
GOTO :EOF
:MakeChoice
CLS
ECHO.
SET "_Temp="
SET "_Choices="
SET /A "_Skipline= !_Amount! - 1"
REM Create Choice List to Display only the choices needed.
FOR %%A IN (%_CharList%) DO (
SET /A "_Temp+=1"
IF !_Temp! LEQ !_Amount! (
IF !_Temp! EQU !_Skipline! (
ECHO.
ECHO.=============================
)
IF DEFINED _Choice.!_Temp!.Value (
SET "_Choices=!_Choices!%%A"
CALL ECHO. %%A : %%_Choice.!_Temp!.Value%%
)
)
)
ECHO.
CHOICE /C !_Choices! /N /M "What File do you want to choose? "
SET "_Chosen=%ERRORLEVEL%"
SET "%~1=!_Choice.%_Chosen%.Value!"
GOTO :EOF
)
You can try this:
#echo off
setlocal enabledelayedexpansion
set jim=
for /f "delims=] tokens=1*" %%a in ('find /v /n "" ^<list.txt') do (
set jim=!jim! %%b
)
echo Select a file from !jim!
set /p file=
type !file!
pause
This will read all lines from the list.txt and return them within a variable !jim!.
I have a folder with many .txt files. I would like to find string "X" in all of these files then I would like to copy the found strings into .txt files into a different folder.
So far I have tried :
#echo on
findstr /m "X" "%userprofile%\Desktop\New_Folder\New_Folder\*.txt"
if %errorlevel%==0 do (
for %%c in (*.txt) do (
type %%c >> "%UserProfile%\Desktop\New_Folder\%%~nc.txt"
pause
I do not understand the output %%~nc.txt part it's suppost to copy the changed .txt files to a new folder with the same name.
I would like to point out that string "X" is found in different places in the .txt file.
This batch file can did the trick (-_°)
So, just give a try : ScanfilesWordSearch_X.bat
#ECHO OFF
::******************************************************************************************
Title Scan a folder and store all files names in an array variables
SET "ROOT=%userprofile%\Desktop"
Set "NewFolder2Copy=%userprofile%\Desktop\NewCopyTxtFiles"
SET "EXT=txt"
SET "Count=0"
Set "LogFile=%~dp0%~n0.txt"
set "Word2Search=X"
SETLOCAL enabledelayedexpansion
REM Iterates throw the files on this current folder and its subfolders.
REM And Populate the array with existent files in this folder and its subfolders
For %%a in (%EXT%) Do (
Call :Scanning "%Word2Search%" "*.%%a"
FOR /f "delims=" %%f IN ('dir /b /s "%ROOT%\*.%%a"') DO (
( find /I "%Word2Search%" "%%f" >nul 2>&1 ) && (
SET /a "Count+=1"
set "list[!Count!]=%%~nxf"
set "listpath[!Count!]=%%~dpFf"
)
) || (
( Call :Scanning "%Word2Search%" "%%~nxf")
)
)
::***************************************************************
:Display_Results
cls & color 0B
echo wscript.echo Len("%ROOT%"^) + 20 >"%tmp%\length.vbs"
for /f %%a in ('Cscript /nologo "%tmp%\length.vbs"') do ( set "cols=%%a")
If %cols% LSS 50 set /a cols=%cols% + 20
set /a lines=%Count% + 10
Mode con cols=%cols% lines=%lines%
ECHO **********************************************************
ECHO Folder:"%ROOT%"
ECHO **********************************************************
If Exist "%LogFile%" Del "%LogFile%"
rem Display array elements and save results into the LogFile
for /L %%i in (1,1,%Count%) do (
echo [%%i] : !list[%%i]!
echo [%%i] : !list[%%i]! -- "!listpath[%%i]!" >> "%LogFile%"
)
(
ECHO.
ECHO Total of [%EXT%] files(s^) : %Count% file(s^) that contains the string "%Word2Search%"
)>> "%LogFile%"
ECHO(
ECHO Total of [%EXT%] files(s) : %Count% file(s)
echo(
echo Type the number of file that you want to explore
echo(
echo To save those files just hit 'S'
set /p "Input="
For /L %%i in (1,1,%Count%) Do (
If "%INPUT%" EQU "%%i" (
Call :Explorer "!listpath[%%i]!"
)
IF /I "%INPUT%"=="S" (
Call :CopyFiles
)
)
Goto:Display_Results
::**************************************************************
:Scanning <Word> <file>
mode con cols=75 lines=3
Cls & Color 0E
echo(
echo Scanning for the string "%~1" on "%~2" ...
goto :eof
::*************************************************************
:Explorer <file>
explorer.exe /e,/select,"%~1"
Goto :EOF
::*************************************************************
:MakeCopy <Source> <Target>
If Not Exist "%~2\" MD "%~2\"
Copy /Y "%~1" "%~2\"
goto :eof
::*************************************************************
:CopyFiles
cls
mode con cols=80 lines=20
for /L %%i in (1,1,%Count%) do (
echo Copying "!list[%%i]!" "%NewFolder2Copy%\"
Call :MakeCopy "!listpath[%%i]!" "%NewFolder2Copy%">nul 2>&1
)
Call :Explorer "%NewFolder2Copy%\"
Goto:Display_Results
::*************************************************************
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "mystring=x"
FOR %%a IN ("%sourcedir%\*.txt") DO FINDSTR "%mystring%" "%%a">nul&IF NOT ERRORLEVEL 1 FINDSTR "%mystring%" "%%a">"%destdir%\%%~nxa"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances and set mystring appropriately, noting that you may have to adjust the findstr switches to accomodate case, literal and space-in-target-string.
Naturally, you could code sourcedir etc. directly as literals, but doing it this way means that the relevant strings need only be changed in one place.
You are close, but checking the ErrorLevel of findstr does not make sense here as this reflects the overall result, that is, ErrorLevel is set to 0 in case any of the files contain the search string.
I would parse the output of findstr /M using a for /F loop and copy the returned files in the body:
for /F "eol=| delims=" %%F in ('
findstr /M /I /C:"X" "%USERPROFILE%\Desktop\New_Folder\New_Folder\*.txt"
') do (
copy "%%F" "%USERPROFILE%\Desktop\New_Folder\"
)
This copies all those files which contain the literal search string (in a case-insensitive manner).
I need a batch file ( Windows CMD is the interpreter, a .bat ) to do this type of task:
1) Search through a folder and its subfolders
2) Find files with the same filename and extension ( aka duplicates )
3) Check if they have the same size
4) If same name + same size, echo all the files except the first one ( practically I need to delete all except one copy )
Thanks for any type of help
This is only an initial script, just for check the files, in a folder and its subfolders, and their size:
#Echo off
Setlocal EnableDelayedExpansion
Set Dir=C:\NewFolder
For /r "%Dir%" %%i in (*) do (
Set FileName=%%~nxi
Set FullPath=%%i
Set Size=%%~zi
Echo "!FullPath!" - SIZE: !Size!
)
Echo.
Pause
This script does what you ask. Just set the ROOT variable at the top to point to the root of your tree.
#echo off
setlocal disableDelayedExpansion
set root="c:\test"
set "prevTest=none"
set "prevFile=none"
for /f "tokens=1-3 delims=:" %%A in (
'"(for /r "%root%" %%F in (*) do #echo %%~znxF:%%~fF:)|sort"'
) do (
set "currTest=%%A"
set "currFile=%%B:%%C"
setlocal enableDelayedExpansion
if !currTest! equ !prevTest! echo "!currFile!"
endlocal
set "prevTest=%%A"
)
But you can make the test more precise by using FC to compare the contents of the files. Also, you can incorporate the DEL command directly in the script. The script below prints out the commands that would delete the duplicate files. Remove the ECHO before the DEL command when you are ready to actually delete the files.
#echo off
setlocal disableDelayedExpansion
set root="c:\test"
set "prevTest=none"
set "prevFile=none"
for /f "tokens=1-3 delims=:" %%A in (
'"(for /r "%root%" %%F in (*) do #echo %%~znxF:%%~fF:)|sort"'
) do (
set "currTest=%%A"
set "currFile=%%B:%%C"
setlocal enableDelayedExpansion
set "match="
if !currTest! equ !prevTest! fc /b "!prevFile!" "!currFile!" >nul && set match=1
if defined match (
echo del "!currFile!"
endlocal
) else (
endlocal
set "prevTest=%%A"
set "prevFile=%%B:%%C"
)
)
Both sets of code may seem overly complicated, but it is only because I have structured the code to be robust and avoid problems that can plague simple solutions. For example, ! in file names can cause problems with FOR variables if delayed expansion is enabled, and = in file name causes a problem with npocmoka's solution.
#echo off
setlocal
for /f "tokens=1 delims==" %%# in ('set _') do (
set "%%#="
)
for /r %%a in (*.*) do (
if not defined _%%~nxa%%~za (
set "_%%~nxa%%~za=%%~fa"
) else (
echo %%~fa
)
)
endlocal
I have the script
for /f "delims=" %%i in ('dir "%folder%*.txt" /b /s') do (
set s=%%i
set s=!s:%folder%=!
set new_s=!s:\=!
if "x!new_s!" NEQ "x!s!" (
:ProcessListSource
For /f "tokens=1* delims=\" %%A in ("!s!") do (
if "%%A" NEQ "" (
if "!Folder1!" NEQ "" (
Set Folder1=!Folder1!\!Name!
)else (
Set Folder1=!Name!
)
Set Name=%%A
)
if "%%B" NEQ "" (
set s=%%B
goto :ProcessListSource
)
)
echo Folder is: !Folder1!
echo Name is: !Name!
echo ---------------------
) else (
echo Not a folder !s!
)
)
but it does not work as I would have expected:
The first for is executed only once and also the last echo is printed on the screen.
Given a folder I need the files from subfolders without the given folder and than split them into the folder and file
Ex: folder=C:\test
The for would give me the file C:\test\test1\test2\t.txt
And I need test1\test2 and t.txt
GOTO breaks your FOR /F \ IF context and they can be executed only once.
More simple example:
#echo off
for /l %%S in (1=1=5) do (
echo %%S
goto :inner_label
rem
:inner_label
rem
)
This will print only 1 . Do you really need the GOTO here?
When the parser reads your code, all the code inside your for loop is "considered" as only one command that is readed, parsed and executed. As stated in the npocmaka answer, any goto call takes you out of this "line" of code, ending the process of the for loop.
This is a alternative. Use pushd + xcopy /l /s commands to generate a list of the relative paths of the files.
#echo off
setlocal enableextensions disabledelayedexpansion
set "folder=%cd%"
pushd "%folder%"
for /f "delims=" %%a in ('xcopy /l /s /y * "%temp%"^|findstr /vbr /c:"[0-9]"'
) do for /f "delims=: tokens=1,*" %%b in ("%%~a") do (
echo [%%c] [%%~nxa]
)
popd