My BAT file loops through all subfolders in a directory, totals their sizes, and inserts the data into a MySQL table. Not working and unsure why [duplicate] - mysql

I've been wrestling trying to get the syntax right on this batch file and I cannot figure out why some things aren't working.
The variable i is not getting incremented each time I do it.
Concatenation on strc doesn't seem to concatenate.
Here is my code:
set i=0
set "strc=concat:"
for %%f in (*.mp4) do (
set /a i+=1
set "str=intermediate%i%.ts"
set strc="%strc% %str%|"
ffmpeg -i "%%f" -c copy -bsf:v h264_mp4toannexb -f mpegts "%str%"
)
set strc="%strc:-1%"
ffmpeg -i "%strc%" -c copy -bsf:a aac_adtstoasc Output.mp4

You are not the first, who fell into the famous "delayed expansion trap" (and you won't be the last).
You need delayed expansion if you want to use a variable, that you changed in the same block (a block is a series of commands within parentheses (and )).
Delayed variables are referenced with !var! instead of %var%.
Reason is the way, cmd parses the code. A complete line or block is parsed at once, replacing normal variables with their value at parse time. Delayed variables are evaluated at runtime.
Two simple batch files to demonstrate:
setlocal EnableDelayedExpansion
set "var=hello"
if 1==1 (
set "var=world"
echo %var% !var!
)
setlocal EnableDelayedExpansion
for /L %%i in (1,1,5) do (
echo %random% !random!
)
Note: A line is also treated as a block:
set "var=old"
set "var=new" & echo %var%
With delayed expansion:
setlocal EnableDelayedExpansion
set "var=old"
set "var=new" & echo !var!
Delayed expansion is per default turned off at the command prompt. If you really need it, you can do:
cmd /V:ON /C "set "var=hello" & echo !var!"
Also there is a way to do the same without delayed expansion (but call costs some time, so it's slower, but if for some reason you can't / don't want to use delayed expansion, it's an alternative):
setlocal DISabledelayedexpansion
for /L %%i in (1 1 5) do (
call echo %random% %%random%%
)
Both methods can also be used to display array-like variables:
(This is often asked like "variable which contains another variable" or "nested variables")
Here is a collection for using such array-like variables in different situations:
With delayed expansion:
setlocal ENableDelayedExpansion
set "num=4"
set "var[%num%]=HELLO"
echo plain delayed: !var[%num%]!
for /L %%i in (4 1 4) do (
echo for delayed: !var[%%i]!
set a=%%i
call echo for delayed with variable: %%var[!a!]%%
)
without delayed expansion:
setlocal DISableDelayedExpansion
set "num=4"
set "var[%num%]=HELLO"
call echo plain called: %%var[%num%]%%
for /L %%i in (4 1 4) do (
call echo FOR called: %%var[%%i]%%
set a=%%i
call echo FOR called with variable: %%var[%a%]%%
)
Note: setlocal has no effect outside of batchfiles, so delayedexpansion works only:
In batch files
When the cmd was started with delayed expansion enabled (cmd /V:ON) (by default, the cmd runs with delayed expansion disabled)
(Follow the links, when you are interested in the technical background or even the advanced technical stuff)

Related

Change character in batch file

Currently i have a csv export with the following output
number;sentence;text;text;text;text;text;text;18.05.2012;time;text;text;number
number;sentence;text;text;text;text;text;text;18.05.2012;time;text;text;number
number;sentence;text;text;text;text;text;text;#;time;text;text;number
number;sentence;text;text;text;text;text;text;#;time;text;text;number
Notice that it sometimes happens that a date is not present, instead "#" has been inserted. The # is also present in other parts of the CSV file, however this shouldn't be impacted. Which currently happens
#echo off
setlocal enableextensions enabledelayedexpansion
(for /f "skip=4 tokens=1-9* delims=," %%f in (input.csv) do if not "%%f"=="" (
set "line=%%f"
set "line=!line:#"=!"
echo(!line!
)) > output.csv
endlocal
Any pointers where i go wrong?
I guess, you didn't quite understand the "tokens" thing. The first token is set to the given variable (%%a), the next tokens are assigned to the (alphabetically) following variables (%%b, %%c, ...). You need to change the ninth token (%%i), so you have to retrieve tokens 1 to 9 and * for "the rest". Also your delimiter was wrong (your text file has ;, so you need delims=;)
#echo off
setlocal enableextensions enabledelayedexpansion
(for /f "skip=4 tokens=1-9* delims=;" %%a in (input.csv) do (
if "%%i"=="#" (set "data=") else (set "data=%%i")
echo(%%a;%%b;%%c;%%d;%%e;%%f;%%g;%%h;!data!;%%j
)) > output.csv
endlocal
(Of course you also could start with %%f, but then your ninth token is %%n - it's easier to read when you start with a)
Keep in mind, consecutive delimiters are treated as one. So if you have empty fields (...;text;;text;...) your tokenization goes wild.

Problems with For Loop

I am using a for loop, and within it, I echo a variable, that updates as the loop goes on. For the format of my code, I have to append everytime it loops. Is there a way for it to overwrite the first time, then on the rest of the for loops, it appends? Here is my code:
#echo off
set file=file
cd %cd%
SETLOCAL ENABLEDELAYEDEXPANSION
for /d %%b in (*) do dir /ad /on /s /b "%%b" >> get_dirs.txt
for /F "tokens=*" %%A in (get_dirs.txt) do (
echo ^<a href="%file%:///%%A"^>%%A^</a^>^<br^> >>index.html
)
pause
So everytime I run this, even when I delete the output file, the html document gets bigger and bigger by duplicating the text inside it so I have the same thing up to over 100 times.
If you want some more backstory of the code head over to my other question that developed some of the code, Command Variable Outputs.
You could use a variable to track whether it is the first iteration or not, and then use an IF/ELSE statement with the same command in each branch, except one uses overwrite, and the other append. But that is needlessly complex.
The simplest thing to do is to delete any existing file before the start of the loop, and then use append in all cases. The append redirection will automatically create the file if it does not yet exist.
#echo off
setlocal
set file=file
del get_dirs.txt
for /d %%b in (*) do dir /ad /on /s /b "%%b" >>get_dirs.txt
del index.html
for /f "delims=" %%A in (get_dirs.txt) do (
echo ^<a href="%file%:///%%A"^>%%A^</a^>^<br^> >>index.html
)
pause
Unless you need "get_dirs.txt" later on, I don't see any need to create that file. you can use FOR /F to directly process the result of the DIR command.
Your code opens the output file, positions the file pointer to the end, and closes the output file once for each iteration. This slows the program down. It is much more efficient (faster) to put parentheses around the entire FOR statement and then use a single redirection. This avoids the need for append mode, so no DEL command is needed.
#echo off
setlocal
set file=file
>index.html (
for /d %%b in (*) do for /f "delims=" %%A in (
'dir /ad /on /s /b "%%b"'
) do echo ^<a href="%file%:///%%A"^>%%A^</a^>^<br^>
)
pause
Here are some additional notes regarding changes I made to your code that are unrelated to your question:
cd %cd% does absolutely nothing useful (change directory to the current directory). So I removed that line.
You enable delayed expansion, but never use it (all your expansion uses %var% instead of !var!). I don't see any need for delayed expansion, and enabled delayed expansion can corrupt FOR variables if they contain !. So I disabled delayed expansion.
I put the SETLOCAL before you define your file variable. No sense in cluttering up your command session environment variable space after your script runs.
Your use of "tokens=" will probably work in real world situations. But technically it is not what you want. It will strip leading spaces from the values. Instead you want to disable delims by using "delims=".

Command Variable Outputs

Basically, I was working on some code, dealing with creating a text file, then later reading the text file line by line, and turning each line into a variable, which is then echoed within other text to make the variable fit into html code, which will later be used in a website. Here is my code:
#echo off
set file=file
cd %cd%
for /d %%b in (*) do dir /ad /on /s /b "%%b" >> get_dirs.txt
for /F "tokens=*" %%A in (get_dirs.txt) do (
echo %%A > tmpfile.txt
set /p t= < tmpfile.txt
pause
echo ^<a href="%file%:///%t%"^>%t%^</a^>
)
pause
Ignore the pauses they were being used for previous debugging. My main problem is that my command prompt is giving me an output of
which is want I want accept my variable %t% is not being echoed with the rest of html code. I can't seem to figure out what is wrong with it. Thank you.
Standard delayed expansion problem. Search SO for hundreds of articles about setlocal delayedexpansion
Your code is written better
for /F "tokens=*" %%A in (get_dirs.txt) do (
echo ^<a href="%file%:///%%A"^>%%A^</a^>
)
If, for reasons you don't reveal, you actually want the variable in t then
for /F "tokens=*" %%A in (get_dirs.txt) do (
set "t=%%A"
echo ^<a href="%file%:///%%A"^>%%A^</a^>
)
will do that, but you'd syill need to either use delayedexpansion or a subroutine to use the dynamic value assigned to t.

Combine CSV files in windows (.cmd or .bat file preferably)

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.

How to create %tab% in CMD

I need reliable way to create %tab% (containing one tab character) for both, Windows and XP.
SET TAB=" "
Should work for Windows 7 (not tested) but not for Win XP (tested).
This
for /F "skip=4 delims=pR tokens=1,2" %%a in ( 'reg query hkcu\environment /v temp' ) do set TAB=%%b
works for Win XP only.
You should use an editor which supports TAB characters without changing them to spaces.
And you should reorder the quotes, as with set TAB=" " you got a variable with three characters.
TAB contains then also the quotes.
set "TAB= "
Currently there seems to be no reliable way to use a program to create a TAB character in all Windows versions on all language platforms.
But you could also use an embedded Jscript snippet.
#if (#X)==(#Y) #goto :Dummy #end/* Batch part
#echo off
SETLOCAL ENABLEEXTENSIONS
for /f "delims=" %%x in ('cscript //E:JScript //nologo "%~f0"') do set TAB=%%x
echo Tab character is "%tab%"
goto :EOF
***** Now JScript begins *****/
WScript.Echo(String.fromCharCode(9));
With robocopy TAB can also be generated.
Robocopy is not available in windows xp by Default.
for /f "delims= " %%T in ('robocopy /L . . /njh /njs') do set "TAB=%%T"
This method will work universally the same on Win2k, WinXP, Vista, Win7, Win8, Win10
It takes advantage of the fact that the MZ header of PE executable images that are produced by Microsoft compiler toolset remained the same from nearly 25 years ago in the days of NT3.1 till today in the days of Windows 10.
The byte value at offset 0x46 of the MZ header is 0x09 which is the TAB character
So it is sufficient to pick any executable file from windows and grab the TAB from it.
And the most convenient and logical option is to use executable of the Command Processor itself.
#echo off
setlocal EnableExtensions
set "TAB="
for /F "delims=" %%Z in (
'^(type "%COMSPEC%"^|^(^(for /L %%P in ^(1^,1^,70^) do #pause^>nul^)^&set /p "TAB="^&call echo^,%%TAB%%^)^)2^>nul'
) do set "TAB=%%Z"
set "TAB=%TAB:~0,1%"
echo,
echo TAB---^>[%TAB%]^<---TAB SPACE---^>[ ]^<---SPACE EMPTY---^>[]^<---EMPTY
echo,
pause
UPDATE April,23,2018
This is an alternate and more understandable syntax which avoid using pipe and is much faster than the above
((for /L %%P in (1,1,70) do pause>nul)&set /p "TAB=")<"%COMSPEC%"
set "TAB=%TAB:~0,1%"
/UPDATE
to echo the TAB use this form:
echo,%TAB%
To write the TAB character to a file:
:: Creates a new file with TAB character
echo,%TAB%>"NewFile.txt"
:: Appends the TAB character to end of the existing file
echo,%TAB%>>"ExistingFile.txt"
Note that echo will always appends a new line (CRLF) at the end. If you just want the TAB character without new line use the prompt technic, but keep in mind that this method is extremely slow compared to echo so don't use it excessively
setlocal
set "prompt=%TAB%"
"%COMSPEC%" /d /k<nul>"TAB_Without_NewLine.txt"
endlocal
Incorporate the tab character into your batch file. In particular, place it on the first line, in front of #ECHO OFF, then read the first line with the SET /P command. It'll read the entire line, of course, so one more SET command will be needed to cut the tab character from the line. Here's an example:
#ECHO OFF
<%0 SET /p tab=
SET tab=%tab:~0,1%
ECHO Every%tab%word%tab%is%tab%tabulated
Note that the spaces preceding #ECHO OFF here are supposed to be a single tab character, like I said earlier.
The obscure forfiles command can be used (or abused?) to generate a tab character (or any other character you prefer, apart from NUL), as discussed in this DosTips topic.
Here it is in a nutshell:
#echo off & setLocal enableExtensions disableDelayedExpansion
for /f "delims= " %%T in ('
forFiles /p "." /m "%~nx0" /c "cmd /c echo(0x09"
') do set "tab=%%T"
echo(words%tab%separated%tab%by%tab%tabs
endLocal & goto :EOF
However, forfiles is only available on Windows Vista and above. But cheer up, my little XP bunnies! You can download a fossilised copy of forfiles.zip (22.1kb) thanks to the wondrous Wayback Machine.
The :makeTab subroutine below creates a tab character and stores it in the name of the variable passed to it. Requires certutil, which is not installed on some versions of Windows XP.
#echo off & setLocal enableExtensions disableDelayedExpansion
call :makeTab tab
echo(words%tab%separated%tab%by%tab%tabs
endLocal & goto :EOF
:makeTab result=
:: returns tab char in var name given as param
:: requires certUtil
setLocal
set "tabFile=%tmp%\tab.tmp"
if not exist "%tabFile%" (
>"%tabFile%" echo(09
certUtil -decodeHex -f "%tabFile%" "%tabFile%" >nul
) %= if =%
for /f "useBack delims=" %%T in ("%tabFile%") do (
endLocal & set "%1=%%T"
) %= for /f =%
exit /b 0 %= makeTab =%
PS: Come to think of it, the above subroutine could be easily extended to generate any character you want (apart from NUL). Watch out for code page issues with characters between ASCII 128 and ASCII 255.
DosTips user aGerman first reported the presence of a tab character in the output from shutdown /? in 2011, and jeb refined the technique for extracting it last May like so:
#echo off & setLocal enableExtensions disableDelayedExpansion
for /f "delims=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 " %%T in ('
shutDown /?
') do set "tab=%%T"
set "tab=%tab:~0,1%"
echo(words%tab%separated%tab%by%tab%tabs
endLocal & goto :EOF
WARNING: Not guaranteed to work across all versions of Windows or all locales. I successfully tested the above on my English language version of Windows 7 HP 32-bit, but ymmv.
I've saved the best for last! ;)
Reluctant as I am to contradict an authority such as jeb, his answer is over 5 years old, and a technique has since been developed to create a tab character using only native batch commands, which works on all versions of Windows from XP onwards.
The :makeTab subroutine below is based on code developed in the marathon Create All ASCII Characters topic on DosTips. It uses makecab to create a tab character (ASCII 9) and stores it as a variable with the name passed to it as a parameter:
#echo off & setLocal enableExtensions disableDelayedExpansion
call :makeTab tab
echo(words%tab%separated%tab%by%tab%tabs
endLocal & goto :EOF
:makeTab result=
:: returns tab char in var name given as param
:: based on http://consolesoft.com/batch/binary/genchr.cmd
setLocal
set "tabFile=%tmp%\tab.tmp"
if not exist "%tabFile%" (goto makeTabFile) else goto readTabFile
:makeTabFile
type nul >"%tabFile%"
makeCab /d compress=off /d reservePerDataBlockSize=0 ^
/d reservePerFolderSize=9 "%tabFile%" "%tabFile%" >nul
for /f "skip=28 delims=" %%F in ('find /v "" "%tabFile%"') do (
>"%tabFile%" echo(%%F
goto readTabFile
) %= for /f =%
:readTabFile
for /f "useBack delims= " %%T in ("%tabFile%") do (
endLocal & set "%1=%%T"
) %= for /f =%
exit /b 0 %= makeTab =%
The subroutine could be easily modified to create any character you prefer (apart from NUL), so long as you know the ASCII code for the character you want. Beware of code page issues between ASCII 128 and 255.
There's no need to "use an editor which supports TAB characters without changing them to spaces".
From command line:
Method 1 - forfiles
echo la >t
forfiles /m "t" /c "cmd /c set /p=j0x09"<nul> tab
Copy /y tab+Nul t
type t | ((for /l %N in (1 1 3) do pause)>nul&findstr "^") > t
copy /y t /A tab /B
Method 2
If you prefer certutil:
set /p=09<nul> t
certutil -decodehex t tab
Method 3: - fsutil
echo la >t
forfiles /m "t" /c "cmd /c set /p=j0x09"<nul> tab
((for /l %N in (1 1 3) do pause)>nul&findstr "^") <tab> t
fsutil file seteof t 1 >nul
Tested on Win 10 cmd
My solution is very simple:
set TAB= "
set "TAB=%TAB:"=%
echo one!TAB!two!TAB!three
one      two      three
Thanks for answers.
Finally I used this simple method:
FOR /f "delims=" %%x IN (delimiter.ini) DO set TAB=%%x