I have files that look like that:
1989_Footer.gif
1989_Header.gif
260273_Footer.gif
260273_Header.gif
...
and I have a CSV that looks like this:
1989;10773387
260273;10776516
...
I want to rename the files number with the one given in the CSV. The first number in the CSV is the old number and the second one (after the semicolon) is the new number. How can I achive that without touching the text after the underline?
I thought about getting the file name, then search the number in the CSV and replace it with the value in the same line after the semicolon.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q40908252.txt"
FOR /f "usebackqtokens=1*delims=;" %%a IN ("%filename1%") DO (
FOR /f "tokens=1*delims=_" %%r IN ('dir /b /a-d "%sourcedir%\%%a_*"') DO (
ECHO(REN "%sourcedir%\%%r_%%s" "%%b_%%s"
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q40908252.txt containing your data for my testing.
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(REN to REN to actually rename the files.
Read the csv file, using ; as the delimiter, placing the from-prefix in %%a and the to-prefix in %%b.
Perform a directory list of files named "%%a_anything" in the source directory, tokenise on _ so that the first token (which must be %%a) goes to %%r and the remainder-of-name to %%s, then rename the file with the prefixes switched.
Assumes that the first _ in the filename will never be a multiple-_
My JREN.BAT regular expression renaming utility can simplify the solution. JREN.BAT is pure script (hybrid batch/JScript) that runs natively on any Windows machine from XP onward - no 3rd party exe file required. Full documentation is available from the command line via jren /?, or jren /?? for paged help.
From within a batch script:
#echo off
for /f "delims=; tokens=1,2" %%A in (rename.csv) do call jren "^%%A_" "%%B_" /fm *.gif
From the command line:
for /f "delims=; tokens=1,2" %A in (rename.csv) do #jren "^%A_" "%B_" /fm *.gif
I would probably do it like that (see the explanatory remarks rem):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_CSV=%~dpn0.csv" & rem // (path to the CSV file holding the old and new numbers)
set "_LOC=%~dp0" & rem // (path to the directory containing the files to rename)
set "_PAT=*.gif" & rem // (pattern of the file name part after the first `_`)
rem // Walk through the CSV file line by line and read old and new numbers:
for /F "usebackq tokens=1-2 delims=,;" %%K in ("%_CSV%") do (
rem // Search files whose names begin with the old number and an `_`:
for /F "delims=" %%F in ('dir /B /A:-D "%_LOC%\%%K_%_PAT%"') do (
rem // Store current file name into variable:
set "NAME=%%F"
rem // Toggle delayed expansion to not lose any `!` in the file name:
setlocal EnableDelayedExpansion
rem // Rename current file by replacing the old number by the new one:
ECHO ren "%_LOC%\!NAME!" "%%L_!NAME:*_=!"
endlocal
)
)
endlocal
exit /B
Remove the upper-case ECHO command after having successfully tested the script!
The advantage of this method is that it works even in case the file name part after the first _ begins with an _ as well; so a file name 1989__some_name.gif would become renamed to 10773387__some_name.gif, so the two consecutive __ are maintained.
Related
i'm trying to split a csv file based on the year. The year is allways shown in UTC Format after first delimiter ";".
example for csv file:
ID;Datum;EUR
1;2021-12-12 12:12:12;50
1;2020-12-12 12:12:12;10
2;2020-12-12 12:12:12;20
1;2019-12-12 12:12:12;80
So far I have the following batch code as a solution.
findstr /I /R /C:"^[^;]*;2019-" "test.csv" > "test_year1.csv"
findstr /I /R /C:"^[^;]*;2020-" "test.csv" > "test_year2.csv"
findstr /I /R /C:"^[^;]*;2021-" "test.csv" > "test_year3.csv"
It works but how can i add the first line (Header) to each of this splitfiles?
Also, the code is a bit simple and unwieldy. Is it possible to automate the whole thing a bit and automatically determine the possible year's from inputfile and create a corresponding output file?
thx for help,
SaXe
#ECHO OFF
SETLOCAL
rem The following settings for the source directory, destination directory, filenames, output filename are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "filename1=%sourcedir%\q71435963.txt"
:: remove variables starting #
FOR /F "delims==" %%b In ('set # 2^>Nul') DO SET "%%b="
:: set environment variables #year#yearnumber# from sourcefile
FOR /f "skip=1usebackqtokens=2delims=-;" %%b IN ("%filename1%") DO SET "#year#%%b#=Y"
:: set "line1" to first line of file
FOR /f "usebackqdelims=" %%b IN ("%filename1%") DO SET "line1=%%b"&GOTO buildfiles
:buildfiles
:: for each year found, create a new file & append data
FOR /f "tokens=2delims=#" %%b IN ('set # 2^>nul') DO (
>"%destdir%\test_%%b.csv" ECHO %line1%
>>"%destdir%\test_%%b.csv" findstr /I /R /C:"^[^;]*;%%b-" "%filename1%"
)
GOTO :EOF
The 2^>nul in each of the set commands suppresses error messages that would occur if there are no variables matching the pattern currently set. The ^ "escapes" the >, telling cmd that the > is part of the set, not of the for.
The usebackq option is only required because I chose to add quotes around the source filename.
--------- Fix for - in column 1:
in place of the for /f "skip... line, use
FOR /f "skip=1usebackqtokens=2delims=;" %%c IN ("%filename1%") DO FOR /f "delims=-" %%b IN ("%%c") DO SET "#year#%%b#=Y"
This assigns the string from the second to third occurrence of ; which grabs the second column to %%c, skipping the first line. Then the variable is set as before using the value of %%c, using - as a delimiter and selects the first token (ie. %%cup to the first delimiter) into %%b as before. The default for tokens= is tokens=1.
I have created batch file to combine all csv file in folder. Below is my batch file code.
#ECHO OFF
SET first=y
SET newfile=Summary.csv
for %%F in (*.csv) do IF NOT %%F==%newfile% (
if defined first (
COPY /y "%%F" %newfile% >nul
set "first="
) else (
FOR /f "skip=1delims=" %%i IN (%%F) DO >> %newfile% ECHO %%i
)
)
My question is, how do i add into the code if i want to add the autosum for every column?
Below is my example csv file after i run the batch file.
Name,A4 Used,A3 Used,Others
A,23,9,2
B,61,41,0
C,5,85,7
I need to create an autosum for every column like example below.
Name,A4 Used,A3 Used,Others
A,23,9,2
B,61,41,0
C,5,85,7
Total,89,135,9
Any idea guys?
This task could be done with following commented batch code depending on contents of processed CSV files:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Exit this batch file if current directory does not contain any CSV file.
if not exist *.csv goto EndBatch
rem The summary CSV file is created first in directory for temporary
rem files to avoid that outer FOR loop below tries to process also
rem the summary file. The summary file is created with header row.
set "NewFile=%TEMP%\Summary.csv"
echo Name,A4 Used,A3 Used,Others>"%NewFile%"
rem Make sure there is no summary CSV file in current directory
rem from a previous execution of this batch file in this directory.
del "Summary.csv" 2>nul
rem Initialize the environment variables for total sum of each column.
set "TotalColumn2=0"
set "TotalColumn3=0"
set "TotalColumn4=0"
rem The outer loop is executed for each CSV file in current directory.
rem The inner loop reads each CSV file line by line. The first line is
rem always skipped. Skipped are also empty lines and lines starting with
rem a semicolon. All other lines are split up into four substrings using
rem comma as separator (delimiter).
for %%I in (*.csv) do (
for /F "usebackq skip=1 tokens=1-4 delims=," %%A in ("%%I") do (
if not "%%D" == "" (
set /A TotalColumn2+=%%B
set /A TotalColumn3+=%%C
set /A TotalColumn4+=%%D
>>"%NewFile%" echo %%A,%%B,%%C,%%D
) else (
del "%NewFile%"
echo ERROR: A line in "%%I" has not four comma separated values.
echo/
pause
goto EndBatch
)
)
)
rem Append to summary file the total sums and move the summary file
rem from temporary files directory to current directory. If that fails
rem unexpected, delete the summary file in temporary files directory.
>>"%NewFile%" echo Total,%TotalColumn2%,%TotalColumn3%,%TotalColumn4%
move "%NewFile%" "Summary.csv" >nul
if errorlevel 1 (
del "%NewFile%"
echo ERROR: Could not move Summary.csv to "%CD%".
echo/
pause
)
:EndBatch
endlocal
Please note the limitations of Windows command interpreter:
Arithmetic expressions can be done only with 32-bit signed integers which means the value range is limited from -2147483648 to 2147483647. There is no support for floating point arithmetic.
Command FOR interprets a sequence of delimiters as one delimiter on splitting up a line into substrings. So a row like D,80,,20 in a CSV file results in loop variable A gets assigned D, loop variable B gets assigned 80, loop variable C gets assigned 20 and loop variable D has nothing assigned. In this case the batch file exits with an error message.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
for /?
goto /?
if /?
move /?
pause /?
rem /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators.
Im trying to build a batch file.
I have 30 csv files in a folder
My intention is
Get each file name (Example is 097_021216_192332.csv)
Extract the first 3 digits
Compare it with a lookup table ( lookup1.bat) against which i have marked another string
EG: lookup1.bat
#echo 107=B_05-
#echo 097=B_06-
#echo 149=B_07-
#echo 109=B_08-
#echo 101=B_09-
#echo 105=B_10-
#echo 098=B_11-
So here i will get "B_06-"
Modify the file name with this "B_06-" prefix and rename the file
Here is my code , i have only basic ideas about looping and im struggling a lot.Thanks for any help.
#echo on
setlocal enabledelayedexpansion
for %%a in ("*.csv") do (
set FileName=%%~na
goto:stepa
goto:eof
)
:stepa
for /f "tokens=1 delims=_" %%a in ("%FileName%") do (
set A=%%a
echo %A%
)
#SET MN=%A%
#FOR /F "tokens=1,2 delims==" %%i IN ('lookup1.bat') DO #IF %%i EQU %MN% SET MW=%%j
#ECHO The board number corresponding to %MN% is %MW%.
set "str=%MW%%FileName%"
echo "%str%"
Ren "!FileName!" "!str!"
:eof
You have a series of problems with the structure of your program. If you want to call a subroutine from inside a for command the right way is using call, not goto, and the goto :eof command must be placed after the for ends. However, this code is simple enough so it don't requires a subroutine.
The table lookup method is more efficient (and also simpler, IMHO) if you use an array to load the table just once, and then directly access its elements via an index.
#echo off
setlocal EnableDelayedExpansion
rem Create the lookup file with lookup1.bat file,
rem this program create lines like this one:
rem 097=B_06-
call lookup1.bat > lookup1.txt
rem Load the lookup table from the file,
rem this method create _array elements_ like this one:
rem set "table[097]=B_06-"
for /F "tokens=1,2 delims==" %%a in (lookup1.txt) do set "table[%%a]=%%b"
rem Process the files in current folder,
rem file name format is this:
rem ###_restOfFileName.csv
for /F "tokens=1* delims=_" %%a in ('dir /A:-D /B *.csv') do (
#ECHO The board number corresponding to %%a is !table[%%a]!.
ren "%%a_%%b" "!table[%%a]!%%b"
)
You may test if the board number is not defined for a file via an additional if not defined table[%%a] ... command placed inside the for.
You may directly create the lookup1.txt file with your text editor; just eliminate all these #echo parts from lookup1.bat and change the extension.
You may review a detailed explanation on array use in Batch files at this answer.
I have read this thread, which helped, but doesn't answer my specific question. I'm hoping someone can help.
I am trying to export a CSV file with TWO COLUMNS of data. Column 1 is the actual filename (with extension), and Column 2 would be the immediate Folder Name (without any path info) of the file location. Question I have is, is that possible? Next question is, how can I export this as a CSV file with two columns of information?
This is a good starting point except this only has the filename (doesn't have the second column that shows the immediate folder name), and this doesn't seem to return to the next line for each filename. Instead this is simply separating with commas and not returning to new lines.
Can you advise if this is possible and offer some ideas?
#echo off
<nul (
for /f "eol=: delims=" %%F in ('dir /b /o:n') do set /p =""%%F","
) >fileList.csv
Thanks everyone!
If by the "Immediate folder name" you mean the name of the containing directory but without the path to that directory, then:
#ECHO OFF
SETLOCAL
PUSHD "%~1"
FOR /f "delims=" %%i IN ("%cd%") DO SET directory=%%~nxi
(
FOR /f "delims=" %%i IN ('dir /b /a-d /on') DO (
SETLOCAL enabledelayedexpansion
ECHO "%%i","!directory!"
endlocal
)
)>filelist.csv
POPD
The pathname of the directory required should be supplied as the first parameter, quoted if necessary.
Essentially, change to the directory in question, find and save the name of the leaf directory, then execute a directory scan returning the filenames. Quote both and output with a comma between. The inner setlocal is to allow at least some silly directory names.
edit 20130422-1421Z
#ECHO OFF
SETLOCAL
PUSHD "%~1"
FOR /f "delims=" %%i IN ("%cd%") DO SET directory=%%~nxi
(
FOR /f "delims=" %%i IN ('dir /b /a-d /on') DO (
SET fdate=%%~ti
SETLOCAL enabledelayedexpansion
ECHO "%%i","!directory!","!fdate:~0,10!"
endlocal
)
)>filelist.csv
POPD
Edited to show date as third element. Quotes retained - remove at will.
If date AND TIME are required, remove the SET fdate line and replace the "!fdate:~0,10!" with "%%~ti
Date and time format - to be certain, need to know the format you are using.
If you're doing a recursive directory search, filename with extension only can be obtained within your for /f loop from %%F by using %%~nxF. That's easy.
The trickier part is scraping the last folder from the path (%%~pF). There's actually an easy trick to that as well though. Use another for loop to get %%~nxI of %%~dpF. Yes, the filename.ext of a full path is the trailing directory.
This only works if the directory does not end in a trailing backslash, though. Since the result of %%~dpF does end in a trailing backslash, you can work around it simply by adding a single dot to the end. So instead of "c:\users\me\Desktop\" you get the ~nx of "c:\users\me\Desktop\." with a trailing dot.
Enough explanation. Here's how it's done.
#echo off
for /f "delims=" %%F in ('dir /s /b /o:n') do (
for %%I in ("%%~dpF.") do echo "%%~nxF","%%~nxI"
) >filelist.csv
I may at various times have .csv files I need to combine. They have the same headers and column layout. I just need a simple way to combine them in Windows 7. The user may not always have excel installed.
A .cmd macro would be great, but the ones I found online don't work.
The best i've got so far is this:
"open a command window ("cmd.exe") and type the following two lines (no brackets)
cd "Desktop\[csv-files]"
type *.csv > my-new-file.csv"
Where the files to be combined are in Desktop\[csv-files].
BUT - it seems to create duplicates (or in some case triplicates) of the combined entries. For instance I have 2 files I tested with 23 and 26 unique entries respectivly. I got out a file with 100 entries and at least one entry repeated 3 times.
Right now the .csv files I am testing are only ~25 entries long, but in time they could be thousands or more.
Sounds like you have an issue with using *.csv and redirecting the output to a .csv file in the same folder. DOS seems to be finding the my-new-file.csv file because of the *.csv and is typing it into itself... You could use a different output filename extension until after the type command finishes, then you could rename the output file... Something like:
cd "Desktop\[csv-files]"
type *.csv > my-new-file.txt
ren my-new-file.txt my-new-file.csv
You can also skip the header of each file after the first, so that you don't end up with file headers throughout the middle of the output file. Try the following:
#echo off
setlocal ENABLEDELAYEDEXPANSION
set cnt=1
cd "Desktop\[csv-files]"
for %%i in (*.csv) do (
if !cnt!==1 (
for /f "delims=" %%j in ('type "%%i"') do echo %%j >> my-new-file.txt
) else (
for /f "skip=1 delims=" %%j in ('type "%%i"') do echo %%j >> my-new-file.txt
)
set /a cnt+=1
)
endlocal
ren my-new-file.txt my-new-file.csv
Explanation:
I used ENABLEDELAYEDEXPANSION to make sure the cnt variable is properly evaluated. When delayed expansion is enabled, you use ! to distinguish variables instead of %. So to evaluate the cnt variable, you use !cnt! instead of %cnt%. Delaying expansion makes it wait to evaluate the value of cnt until the moment that it is used. Sometimes, but not always, if you use %cnt%, it will equal a value from a previous iteration. If you enable delayed expansion and use !cnt!, it will always evaluate the correct current value.
By setting cnt to 1, we can run different code for the 1st .csv file that is processed. The code includes all lines from the 1st .csv file, but skips the first line of all subsequent .csv files.
I used a nested for loop. The outer for cycles through all .csv files in the current folder. The inner for loop executes the type "%%i" command, where %%i is the name of the .csv file. Each line of the file is processed individually as %%j, which is passed to the echo %%j command. echo would normally print the value for %%j to the command prompt window. However, you can redirect the output to a file using > or >>. The > redirector overwrites the output file with the new value. The >> redirector appends the new value to the output file. Since each line of each file, and each file is being processed individually, we must use the >> redirector to push all content into a single file.
When using the for /f command, the output is broken into individual parts using the specified delimiter. The default delimiter is a space. If I didn't include "delims=", then the text This is fun would be broken into the following:
%%j = This
%%k = is
%%l = fun
We want to process the whole line from the .csv file all-at-once. By setting the delimiter to nothing ("delims="), the whole line can be processed using %%j.
For more specific help about how the for command works, type for /? at a command prompt.
endlocal reverts the environment to its state at the point where setlocal was used. Any variables you declared are removed, and extensions are set back to their prior value.