Escape variable in Batch - batch-file

I have a piece of code:
for /F "tokens=*" %%A in (myfile.txt) do (
echo echo %%A ^>^>myfile.txt>>myfile.bat
)
As some of you can see, this code reads myfile.txt, and creates myfile.bat, which when opened creates an exact copy of the original myfile.txt. The problem comes in when myfile.txt contains special characters, such as >. How can I escape the %%A variable?
any help is appreciated.

I have this idea : using Certutil command to encode your text file and generate it again like this batch script can do :
#echo off
set "MyTxtFile=myfile.txt"
for %%i in (%MyTxtFile%) do (
set "MyBatchFile=%%~ni.bat"
set "TempFile=%%~ni.B64"
Set "NewFile=%%~ni__%%~xi"
)
#for /f %%i in ("certutil.exe") do if not exist "%%~$path:i" (
echo CertUtil.exe not found.
pause
exit /b
)
Rem to encode your text file to a temporary file
Certutil -encode "%MyTxtFile%" "%TempFile%" >nul 2>&1
(
echo #echo off
echo Title Generate code of "%MyTxtFile%" to "%NewFile%"
echo CERTUTIL -f -decode "%%~f0" "%NewFile%" ^>nul 2^>^&1
echo Exit
)> "%MyBatchFile%"
#Copy "%MyBatchFile%" /b + "%TempFile%" /b >nul 2>&1
Del "%TempFile%" >nul 2>&1
Timeout /T 2 /NoBreak>nul & exit
EDIT
This code can generate what you want based on your last comment test >> Hello :
#echo off
Title Generate code of "myfile.txt" to "myfile__.txt"
CERTUTIL -f -decode "%~f0" "myfile__.txt" >nul 2>&1
Exit
-----BEGIN CERTIFICATE-----
dGVzdCA+PiBIZWxsbw0KDQo=
-----END CERTIFICATE-----

The following commented code snippet could help (see Variable Edit/Replace):
#ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
rem silently create empty output files - just for testing
>NUL COPY /Y NUL myfile46134196.bat
>NUL COPY /Y NUL myfile46134196ou.txt
for /F "tokens=*" %%A in (myfile46134196in.txt) do (
set "_aux=%%A"
rem replace every `Greater Than` symbol with a properly escaped one
echo echo !_aux:^>=^^^>! ^>^>myfile46134196ou.txt>>myfile46134196.bat
rem ^> properly escape `Greater Than` symbol - input string
rem ^> -output string
rem ^^ add a caret (Circumflex Accent) to output string
)
rem debugging outputs
echo ON
type myfile46134196.bat
#ECHO OFF
rem test: run currently created .bat file
call myfile46134196.bat
rem test: and show result
echo ON
type myfile46134196in.txt
type myfile46134196ou.txt
#ECHO OFF
Output:
==> .\so\46134196.bat
==> type myfile46134196.bat
echo test^>^>hello >>myfile46134196ou.txt
==> type myfile46134196in.txt
test>>hello
==> type myfile46134196ou.txt
test>>hello
==>
Further resources (required reading, incomplete):
(command reference) An A-Z Index of the Windows CMD command line
(helpful particularities) Windows CMD Shell Command Line Syntax
(%A etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
(> etc. special page) Redirection
(^ caret) Escape Characters, Delimiters and Quotes

Related

Log contents of text file before deleting

My script isn't logging the contents of run.txt to log.txt
I've tried to remove the delete command to see if it was deleting it too quickly and therefore couldn't log. But that wasn't the case.
What should I change?
#ECHO OFF &setlocal
SET File=run.txt
type %File%
for /f "tokens=*" %%A in (%File%) do (echo >> log.txt)
del "%File%" /s /f /q > nul
pause
Here is a very simple way to do the task you are requiring.
#echo off
REM Will only grab the first line of the file
set /p file=<run.txt
REM For the last line use a for loop
for /f "tokens=*" %%a in (%file%) do set last_line=%%a
(
echo %file%
)>>log.txt
del /f %file% >nul
If not %errorlevel% equ 0 (
ECHO ERROR - %errorlevel%
pause
exit /b
)
ECHO Success!
timeout /t 003
exit /b %errorlevel%
EXPLANATION
set /p is for set prompt. For more information you can use set /? in your CMD window or check out this site.
I wish I could speak more on what < does, but what it is doing here is piping the content of run.txt to our variable.
Then we echo out our variable to our log file with (ECHO This is our %file%)>>destination
>> is to append where > is to overwrite the file.
(
echo %file%
echo.
)>>%file%
Checking for an error is probably unnecessary, but I believe it is a good habit to build on which is what I am trying to do with that If not %errorlevel% statement.
No error? We Success and timeout ourselves for xxx seconds.
Try:
#ECHO OFF &setlocal
SET "File=run.txt"
type "%File%" >> "log.txt" && (del "%File%" /f > nul)
pause

Convert batch script into base64 / non-readable format

Years ago I saw some batch scripts that contain nothing relevant at a fist look, but with a lot of content. The content was base64 encoded, and when you run the scripts, they are just running the commands that are encoded there.
Something like
SET mypath=%~dp0
echo "%mypath%
will look similar with
some_base_64_decoding_function(
U0VUIG15cGF0aD0lfmRwMA0KIGVjaG8gIiVteXBhdGgl
)
I don't really remember how those file were, and I can't find anything relevant on the Internet, except this article: Convert PowerShell script into non-readable format
but this only refeer to PowerShell scripts, and I need it for .bat scripts.
Anyone to give me a hint?
This is a sample batch file for encoding files in Base 64 with Certutil utility.
How to use it?
Just save this code on your notepad or on notepad++ or on any text editor as :
Certutil_B64_Encoding_Files.bat and drag and drop any file over it to be encoded
#echo off
Title Encoding files with CERTUTIL utility by Hackoo 2017
color 0A & Mode 83,3
If "%~1"=="" (
color 0C & Mode 80,3
echo(
echo You must drag and drop a file over this batch script to be encoded !
Timeout /T 5 /nobreak>nul & exit /b
)
#for /f %%i in ("certutil.exe") do if not exist "%%~$path:i" (
echo CertUtil.exe not found.
pause
exit /b
)
set "TempFile=%Temp%\Temp_b64
set "OutputFile=%~nx1_encoded%~x0"
If exist "%OutputFile%" Del "%OutputFile%" >nul 2>&1
echo(
echo Please wait a while ... Encoding "%~nx1" is in progress ...
certutil.exe -f -encode "%~1" "%TempFile%" >nul 2>&1
(
echo #echo off
echo CERTUTIL -f -decode "%%~f0" "%%Temp%%\%~nx1" ^>nul 2^>^&1
echo Start "%~n1" "%%Temp%%\%~nx1"
echo Exit
)>> "%OutputFile%"
copy "%OutputFile%" /b + "%TempFile%" /b >nul 2>&1
If exist "%TempFile%" Del "%TempFile%" >nul 2>&1
Timeout /T 2 /NoBreak>nul & exit
Encoded HTA Example: CommandLine.hta_encoded.bat
This is a result of an encoded output of a HTA file of mine named as CommandLine.hta_encoded.bat
So, you should copy and paste this code as CommandLine.hta_encoded.bat and execute it by double click. And you will get something like this :
Encoded VBS Example : DJBuzzRadio.vbs_encoded.bat
#echo off
CERTUTIL -f -decode "%~f0" "%Temp%\DJBuzzRadio.vbs" >nul 2>&1
Start "DJBuzzRadio" "%Temp%\DJBuzzRadio.vbs"
Exit
-----BEGIN CERTIFICATE-----
UGxheSAiaHR0cDovL3d3dy5jaG9jcmFkaW9zLmNoL2RqYnV6enJhZGlvX3dpbmRv
d3MubXAzLmFzeCINClN1YiBQbGF5KFVSTCkNCiAgIERpbSBTb3VuZA0KICAgU2V0
IFNvdW5kID0gQ3JlYXRlT2JqZWN0KCJXTVBsYXllci5PQ1giKQ0KICAgU291bmQu
VVJMID0gVVJMDQogICBTb3VuZC5zZXR0aW5ncy52b2x1bWUgPSAxMDANCiAgIFNv
dW5kLkNvbnRyb2xzLnBsYXkNCiAgIGRvIHdoaWxlIFNvdW5kLmN1cnJlbnRtZWRp
YS5kdXJhdGlvbiA9IDANCiAgICAgICB3c2NyaXB0LnNsZWVwIDEwMA0KICAgbG9v
cA0KICAgd3NjcmlwdC5zbGVlcCAoaW50KFNvdW5kLmN1cnJlbnRtZWRpYS5kdXJh
dGlvbikrMSkqMTAwMA0KRW5kIFN1Yg0K
-----END CERTIFICATE-----
MACRO-b64decode.bat
#echo off
SETLOCAL DISABLEDELAYEDEXPANSION
::DEFINITIONS
( set LF=^
%= EMPTY =%
)
set ^"NL=^^^%LF%%LF%^%LF%%LF%^^"
set $MACRO.ForEntireLine=^^^^^^^"eol^^^^=^^^^^^^%LF%%LF%^%LF%%LF%^^^%LF%%LF%^%LF%%LF%^^^^ delims^^^^=^^^^^^^"
::MACRO
ENDLOCAL &^
set $MACRO.b64exec=FOR %%? in (args main) do if "%%?" == "main" (%NL%
FOR %%a in (!args!) do (%NL%
^>encoded.txt echo %%a%NL%
^>nul certutil -decodehex encoded.txt decoded.txt 1%NL%
FOR /F %$MACRO.ForEntireLine% %%x in (decoded.txt) do %%x%NL%
del /F /Q encoded.txt decoded.txt%NL%
)%NL%
) ELSE SETLOCAL ENABLEDELAYEDEXPANSION ^& set args=
To call the macro inside your batch file:
call MACRO-b64decode.bat
%$MACRO.b64exec% ZWNobyBoZWxsbywgd29ybGReIQ==
which will output:
hello, world!
Note: DELAYEDEXPANSION is enabled

CMD Batch and 7z : Capture the progress of the extraction

I'm trying to extract something using the 7zip command line tool from a batch file
and i want just the percentage progress to appear
my code is
#echo off
for /f "tokens=3 delims=. " %%i in (
'7z x "file.rar" ^| findstr /b /r " [0-9][0-9]*\%%"'
) do (
cls
echo %%i
)
PAUSE
but all i get out is just blank during the whole extracting progress .
what went wrong?
The problem is that a FOR /F take the whole output of a command and when the command is finished it begins to iterate over the lines.
Well, this can't be used to solve your task.
But you can pipe the output to another process, in this sample I use the same batch as the second process ( %~f0 is the batch itself )
#echo off
setlocal EnableDelayedExpansion
if "%~1"==":pipe" goto %~1
7z x "file.rar" | findstr /b /r " [0-9][0-9]*\%%" | "%~f0" :pipe
echo Ready
exit /b
:pipe
set "line="
set /p line=
if defined line (
echo #### !line!
goto :pipe
)

Replace line in config file with batch afterward start exe

With a batch file, I want to change a value in a configuration file:
"title.connectionString" : "ServerIP",
ServerIP is the variable to be changed. So the batch file has to give people who use it an option to choose from 4 prefixed IPs. After they selected one of the 4 the IP, the config file has to be saved with new value and the batch file should run an executable.
Has anyone got an idea how I can do this with a batch file?
Easy, try this code:
#echo off
:start
Echo Select Ip:
Echo.
Echo 1. 10.0.0.0
Echo 2. 10.0.0.1
Echo 3. 10.0.0.2
Echo 4. 10.0.0.1
Echo.
Choice /c 1234 /m "Ip: " /n
set choice=%errorlevel%
set ip=
if %choice%==1 set ip=10.0.0.0
if %choice%==2 set ip=10.0.0.1
if %choice%==3 set ip=10.0.0.2
if %choice%==4 set ip=10.0.0.3
if "%ip%"=="" (Echo Error, null variable & goto :start)
ren config.txt config.tmp
setlocal Enabledelayedexpansion
for /f "tokens=*" %%a in (config.tmp) do (
set line=%%a
Echo !line:ServerIP=%ip%! >> config.txt
)
del config.tmp
And that should do what you want.
Mona
#echo off
setlocal enableextensions
call :replaceKeyValue "file.config" "title.connectionString" "123456789"
endlocal
exit /b
:replaceKeyValue file key value
setlocal enableextensions disabledelayedexpansion
ren "%~f1" "%~nx1.tmp" >nul && (
(for /f tokens^=1^,*^ delims^=^:^ eol^= %%k in ('findstr /n "^" ^<"%~f1.tmp"') do (
echo(%%l|findstr /c:"\"%~2\"" >nul && (
for /f "tokens=1 delims=:" %%v in ("%%l") do echo(%%~v : "%~3",
) || (
echo(%%l
)
)) > "%~f1"
del "%~f1.tmp" > nul
)
endlocal
This will handle the replacement of the value in the file. Monacraft answer shows a perfect way of selecting the required ip.
This will rename the file to file.tmp and for each line in the file (findstr /n is used to avoid lost of empty lines) it is tested agains the passed key. When required line is found, it is split using the colon (to keep the indentation) and value replaced with supplied value. All the non matching lines are echoed as is. All the output of the process is send to the original file and at end, the .tmp file is deleted.

Batch File Loop Skip File if name contains

I am creating this batch file, that works with handbrakecli, to batch convert avi to mp4.
However I am stuck in how to continue the loop and skip the current file inside a loop.
FOR /R "%somepath%" %%G in (*.avi) DO (
rem skip if filename contains word trailer
rem skip if file name contains word sample
rem do conversion
)
This currently doesn't work in skipping the files that contain trailer or sample
I have tried using find or findstr and both fail to skip.
echo "%%G" | c:\windows\system32\findstr /i "trailer" > NUL
If %ERRORLEVEL% EQU 1 set skip Yes
Here is for sample.
echo "%%G" | c:\windows\system32\findstr /i "sample" > NUL
If %ERRORLEVEL% EQU 1 set skip Yes
If a file contains either trailer or sample, I do not want to do any handbrakecli conversions, but to just skip it.
I do echo's to display which files get converted, and it does include files with Sample or sample in the name.
I have tried using find or findstr and both fail to set skip to yes
if skip == No do ( rem do conversion )
I only want to convert non-trailer/sample avi files.
Thank you for your time.
try this, put your conversion commands in the loop and remove the word echo before handbrakecli if the output is OK:
#echo off &setlocal
FOR /R "%somepath%" %%G in (*.avi) DO (
set "fpath=%%G"
set "fname=%%~nG"
setlocal enabledelayedexpansion
if "!fname!"=="!fname:trailer=!" if "!fname!"=="!fname:sample=!" (
echo handbrakecli.exe "!fpath!" &rem put your conversion command here
>>"logfile.log" echo !fname!
)
endlocal
)
The file name+file path is in the variable "!fpath!".
Added some code concerning the needs of the OP:
#echo off &setlocal
rem replace avi with mp4 files in my movie folder
rem grab 4 random folders with avi in them and no mp4
rem Settings for this Batch File
set "moviepath=H:\Movies"
set "logfile=C:\Documents and Settings\%USERNAME%\LogFiles\avi_converter.log"
rem check if log file exists
if not exist "%logfile%" echo(>"%logfile%"
rem create empty convert file
copy nul "convert_movies.bat" >nul 2>&1
rem add echo off
echo #echo off >>"convert_movies.bat"
rem set counter
SET /A COUNT=1
FOR /R "%moviepath%" %%G in (*.avi) DO (
set "fpath=%%~fG"
set "fname=%%~nG"
setlocal enabledelayedexpansion
rem check if count greater than 4
if !COUNT! gtr 4 goto:eof
if "!fname!"=="!fname:trailer=!" if "!fname!"=="!fname:sample=!" (
rem echo handbrakecli.exe "!fpath!" &rem put your conversion command here
rem Send File To HandBrakeCLI
CALL :DOHandBrakeCLI "!fpath!"
rem Delete File
CALL :DeleteOldFile "!fpath!"
rem Add Log Entry
CALL :LogEntry "!fpath!"
rem add line break space
echo( >>"convert_movies.bat"
endlocal
rem increment counter
SET /A COUNT+=1
) else endlocal
)
rem end main program, to close cmd window replace it with EXIT
goto:eof
:DOHandBrakeCLI
rem skip if the parameter is empty
IF "%~1"=="" goto:eof
For %%A in ("%~1") do (
Set "Folder=%%~dpA"
Set "Name=%%~nxA"
)
rem echo %Folder%%Name%
echo start /b "" "c:\handbrakecli\HandBrakeCLI.exe" -i "%~1" -o "%Folder%%~n1.mp4" --preset="High Profile">>"convert_movies.bat"
exit /b
:DeleteOldFile
rem skip if the parameter is empty
IF "%~1"=="" goto:eof
For %%A in ("%~1") do (
Set "Folder=%%~dpA"
Set "Name=%%~nxA"
)
rem sends parameters to deletefile which will make sure new file exists before deleting old one
echo c:\projects\deletefile.bat "%~1" "%Folder%%~n1.mp4">>"convert_movies.bat"
exit /b
:LogEntry
rem skip if the parameter is empty
IF "%~1"=="" goto:eof
echo "%~1">>"%logfile%"
exit /b
This should work:
#echo off
FOR /R "%somepath%" %%G in (*.avi) DO (
echo "%%~nG" |findstr /i "trailer sample">nul || (
rem do conversion
)
)
It's difficult to see where your post is pseudocode and where actual code.
The first sample contains only REM statements, so it's not surprising it apparently does nothing.
Your second and third sample are effectively identical - the only difference is the target string. It's not surprising that the variable skip isn't set to Yes since the correct syntax is
if %errorlevel% equ 0 set skip=Yes
The syntax you've posted will REPORT that skip is not defined - it ignores the Yes
HOWEVER this syntax is only usable OUTSIDE of a "block statement" - that is, a multiple-instruction statement (enclosed in parentheses) or cascaded&by&ampersands. Batch first PARSES a complete statement - from the FOR or if through to the appropriate closing-parenthesis and THEN executes it. As part of the PARSING phase, any %var% - including %errorlevel% is replaced by its value as it stands at the time the entire statement is parsed - not as it changes due to the operation of the for.
In order to use the value as it changes, you need to use
if errorlevel 1 (do_something) else (do_something_else)
where do_something and do_something_else) may themselves be compound statements.
OR
if defined variable (do_something) else (do_something_else)
where the variable either is defined or not
OR
setlocal enabledelayedexpansion
....
if !errorlevel! equ x (do_something) else (do_something_else)
OR
if !var! neq something (do_something) else (do_something_else)
But it's quite possible that
FOR /R "%somepath%" %%G in (*.avi) DO (
echo(%%G|findstr /i "sample trailer" >nul
if errorlevel 1 echo %%G
)
will give you an appropriate skeleton.
Echo the filename through FINDSTR and look for "sample" or "trailer" /i case-insensitive. Findstr sets errorlevel 0 if either target string is found, 1 otherwise - and the if errorlevel x syntax works on the dynamic value of errorlevel within a loop.
#ECHO on &SETLOCAL
REM This script was inspired by Endoro's expanded script
(https://stackoverflow.com/a/16891696/10572786).
REM This batch script will recursively search for all .mp4 files that don't
have (x265) in the file name. Any valid results will be encoded with x265
using FFmpeg. The original .mp4 file will remain unchanged in it's original
folder with the new x265 version.
REM Example: %PATH%\A.mp4 > %PATH%\A(x265).mp4
REM If you don't have ffmpeg.exe on your PC you must download or build it
with Microsoft Visual Studios. I recommend you download and run media
autobuild suite on GitHub: (https://github.com/jb-alvarado/media-
autobuild_suite).
REM Once ffmpeg is compiled/downloaded make sure to set it's folder path as
an environmental variable in Windows before running the script. Change the
script's working directory to your .mp4 files root folder using the "cd"
command.
REM !!BEGIN SCRIPT!!
cd /d %USERPROFILE%\Desktop\Vids\
REM or perhaps use [cd /d %OneDrive%\Desktop\Vids]
REM Set mp4PATH to the root folder you wish to recursively search.
SET "mp4PATH=%USERPROFILE%\Desktop\Vids\"
REM Create empty convert file.
COPY NUL "convert_movies.bat" >NUL 2>&1
REM Add ECHO off.
ECHO #ECHO off >>"convert_movies.bat"
REM Recursively search root folder.
FOR /R "%mp4PATH%" %%G IN (*.mp4) DO (
SET "fpath=%%~fG"
SET "fname=%%~nG"
SETLOCAL enabledelayedexpansion
REM Ignore all files that have "(x265)" in the file name.
IF "!fname!"=="!fname:*(x265)=!" (
CALL :DO_FFmpeg_CLI "!fpath!"
ECHO(>>"convert_movies.bat"
) ELSE ENDLOCAL
)
)
GOTO:EOF
REM CALL variables for use in FFmpeg's command line.
:DO_FFmpeg_CLI
IF "%~1"=="" GOTO:EOF
FOR %%I IN ("%~1") DO (
SET "Folder=%%~dpI"
SET "Name=%%~nxI"
)
REM Export info to "convert_movies.bat and run ffmpeg.exe's command line in the cmd.exe window.
ECHO ffmpeg -y -i "%~1" -c:v libx265 -preset slow -crf
18 -c:a aac "%Folder%%~n1(x265).mp4">>"convert_movies.bat" && ffmpeg |
ffmpeg -y -i "%~1" -c:v libx265 -preset slow
-crf 18 -c:a aac "%Folder%%~n1(x265).mp4"
EXIT /B
PAUSE
The Batch file below solve the original question AND limit the number of converted files to a given number (that does not appear in the original question):
#echo off
setlocal EnableDelayedExpansion
rem Insert in the next line the list of files to skip
set skip=/trailer/sample/
set count=0
FOR /R "%somepath%" %%G in (*.avi) DO (
if /I "!skip:/%%~nG/=!" equ "%skip%" (
echo Current file name is not in skip variable
echo Do conversion on: %%G
set /A count+=1
if !count! equ 20 goto :endLoop
)
)
:endLoop
echo Converted files: %count%

Resources