At work I need to create a .bat script that reads the first 2 chars on the first line, of multiple files, and then echo them to the screen.
So far I have this:
#echo off
setlocal enabledelayedexpansion
for /r I:\Test\Filer %%F in (*.*) do (
set first2 =<%%F
set first2=%first2:~0,2%
echo %first2%
)
But all it writes is: ECHO is off
Anyone got an idea what I have done wrong?
You are missing /p! This should work:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /r I:\Test\Filer %%F in (*.*) do (
SET /p first2=<%%F
SET first2=!content:~0,2!
ECHO !first2!
)
PAUSE
#echo off
setlocal enabledelayedexpansion
for /r I:\Test\Filer %%F in (*.*) do (
set /p first2=<%%F
set "first2=!first2:~0,2!"
echo(!first2!
)
In delayedexpansion mode, %var% is the value of var at parse-time and !var! is the run-time value.
The ( in the echo will ensure that a newline is shown if var is not set (or "set" to a zero-length string)
The quotes in a set statement ensure that trailing spaces are not included in the value assigned to the variable.
Note that spaces are not allowed after the variablename in a string "set" statement; a variable with a trailing space in its name will be set, and this is not the same as the variable with no space in its name.
set /p is required to assign a value from a file. Be carefu of zero-length files and files containing a newline (CR LF) at the start!
Delayed Expansion will cause variables to be expanded at execution time rather than at parse time, this option is turned on with the SETLOCAL command. When delayed expansion is in effect variables may be referenced using !variable_name! (in addition to the normal %variable_name% )
#echo off
setlocal enableextensions enabledelayedexpansion
for /r I:\Test\Filer %%F in (*.*) do (
set /p first2=<"%%~F"
set "first2=!first2:~0,2!"
echo !first2!
)
Here in set /p first2=<"%%~F" use double quoted "%%~F" (for a case if a path or file name contains e.g. space) and ~ modifier (to avoid doubling of double quotes)
Resources:
EnableDelayedExpansion
Command Line arguments (Parameters) and their ~ modifier(s)
Related
The file is not added in the destination path if it has spaces in the file name.
For example, if the filename is textfile1.txt -> it will be added in the destination path. However, if the directory filename has space like this text file4.txt it will not be added.
Is there a way to remove the spaces of the filename?
Here is the image:
Here is my main concern:
Here is my script:
#ECHO off
TITLE (c) ASDG
SETLOCAL EnableDelayedExpansion
SET locationPath=C:\Textfiles\
SET destinationPath=E:\Textfiles\
SET status=success
SET countMetadata=0
SET countPDF=0
SET countJPEG=0
ECHO Executing the program...
FOR /R %locationPath% %%g IN (*.txt) DO (
CD %%~dpg
IF EXIST *.txt* (
FOR /F "skip=1 tokens=1* delims=|" %%a IN (%%~nxg) DO (
SET /a countMetadata+=1
ECHO %%~dpa%%a^| %%b >> %destinationPath%^%%~nxg
)
IF %status% == success (
ECHO %%g has been successfully added
ECHO %%g >> %destinationPath%^logs.txt
)
)
)
After reformatting to use indentation to show code blocks (parenthesised code that is parsed, substituting %variables%, then executed), I then applied various recommendations:
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.
Use set /a to assign numeric values. No quotes required.
THIS CODE WILL NOT FULLY PERFORM THE REQUIRED TASK
Without comments to explain why some code is used, it's difficult to provide guidance.
#ECHO OFF
SETLOCAL EnableDelayedExpansion
TITLE (c) ASDG
SET "locationPath=C:\Textfiles"
SET "destinationPath=E:\Textfiles"
SET "status=success"
SET /a countMetadata=0
SET /a countPDF=0
SET /a countJPEG=0
ECHO Executing the program...
FOR /R "%locationPath%" %%g IN (*.txt) DO (
CD %%~dpg
IF EXIST *.txt* (
FOR /F "usebackq skip=1 tokens=1* delims=|" %%a IN ("%%~nxg") DO (
SET /a countMetadata+=1
ECHO %%~dpa%%a^| %%b >> %destinationPath%\%%~nxg
)
IF !status! == success (
ECHO %%g has been successfully added
ECHO %%g >> %destinationPath%\logs.txt
)
)
)
GOTO :EOF
Modifications explanation
I prefer the setlocal to be the second line. YMMV.
Set commands modified as explained above
locationpath in the for /R quoted - it may contain separators like spaces.
%%~nxg quoted in for...%%a as it may contain spaces
usebackq added to for...%%a as %%~nxg is now quoted
I prefer to avoid ADFNPSTXZ (in either case) as metavariables (loop-control variables)
ADFNPSTXZ are also metavariable-modifiers which can lead to difficult-to-find bugs
(See `for/f` from the prompt for documentation)
Not sure what is going on with the following echo, but destinationPath no longer has the terminal \. Same comment applies to the following ECHO %%g.
!staus! replaces %status% (logically) as logically, status may change within the block - the delayed expansion trap
BUT status is not being varied within the block, so its value will always be its initial value, success.
Using Boolean
So - a few things for OP to clean up...
I have the following Batch script which replaces occurrences of {path} in a text file with a path:
#echo off
setlocal EnableDelayedExpansion
set myPath=C:\Program Files (x86)\foo
for /F "tokens=*" %%A in (template.txt) do (
set line=%%A
set line=!line:{path}=%myPath%!
echo !line!
)
When I run this script I get the error message
\foo! was unexpected at this time.
If I remove the parentheses in the path it works as expected. How can I solve this problem? I cannot have quotes around the path in the text file so putting quotes around the path in the set statement is not an option.
#echo off
setlocal EnableDelayedExpansion
set "mypath=C:\Program Files (x86)\foo"
for /F "tokens=*" %%A in (q71593680.txt) do (
set "line=%%A"
CALL :changeline
echo !line!
)
FOR %%c IN ("%mypath%") DO for /F "tokens=*" %%A in (q71593680.txt) do (
set "line=%%A"
set "line=!line:{path}=%%~c!"
echo !line!
)
GOTO :EOF
:changeline
set "line=!line:{path}=%mypath%!"
GOTO :eof
The problem is that the ) in the substitution-string is being taken as the closing parenthesis of the do.
Solution : make an internal subroutine as shown.
Use set "var1=data" for setting string values - this avoids problems caused by trailing spaces.
Don't use path as a variablename - it's a reserved word in batch, meaning the sequence in which the directories are searched to find an executable that isn't in the current directory.
Use set path=%ProgramFiles(x86)%\foo first (this folder may be elsewhere, this variable is here to find it anyway), and surround the replacement set with quotes (see below).
Corrected program:
#echo off
setlocal EnableDelayedExpansion
set pathval=%ProgramFiles(x86)%\foo
for /F "tokens=*" %%A in (template.txt) do (
set line=%%A
REM Please note the quotes around the affectation. It avoids an interpretation.
set "line=!line:{path}=%pathval%!"
echo !line!
)
Side note: even with setlocal, avoid to name a variable path...
So I know how to do simple string replacing with the SET command.
Example:
set /p a=
set a=%a:<=^<%
echo %a%
(This example will change the prompted variable to the same thing but with the < character to be ^< to be be properly echoed if needed to)
I want to do the same thing but with the % character but I can't get it to work.
#ECHO OFF
SETLOCAL
SET "something=%%he%%llo%%"
ECHO %something%
ECHO ============
SETLOCAL ENABLEDELAYEDEXPANSION
SET "anotherthing=!something:%%=x!"
endlocal&SET "anotherthing=%anotherthing%"
ECHO %something%
ECHO %anotherthing%
GOTO :EOF
Like this, you mean?
There was nothing wrong with your method, short of using doublequotes to protect from poison characters.
The main issue now, is in trying to see the content, because you'd be Echoing poison characters. To see it actually in place I included two methods, a Set command to list all variables beginning with a, (with a findstr thrown in to isolate only the one named a), and by using delayed expansion, which prevents the variable from being expanded when the command line is read/parsed. At the very bottom I included a method of showing it with the Echo command without using delayed expansion or doublequotes, as you can see to escape a caret, ^, you'll need in this case to use two more carets
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "a="
Set /P "a="
Set "a=%a:<=^<%"
Echo(%a%
Pause
(Set a) 2> NUL | %SystemRoot%\System32\findstr.exe /B /L /I "a="
Pause
SetLocal EnableDelayedExpansion
Echo(!a!
EndLocal
Pause
Echo(%a:^<=^^^<%
Pause
The full (known) rules for variable replacement can be found at SO:
Percent Expansion Rules
In short:
The search expression in a percent replacement expression can not start with a percent.
The search expression in a delayed replacement expression can not start with a exclamation mark.
But you can replace percent signs with delayed expression
setlocal EnableDelayedExpansion
set /p var=
set "var=!var:%%=REPLACE!"
echo(!var!
The percent sign itself has to be doubled here, because it collapse to a single percent in phase2 (percent expansion)
I am making a batch file and I'm trying to print out the path of every file in a folder but with double backslashes
#echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
for /r %%i in (%USERPROFILE%\*) do (
set route=%%i
set route=%%i:\=\\%%
echo %%route%% >> output.txt
)
The expected values for every data are for example:
Output.txt
C:\\Users\\myuser\\...
C:\\Users\\myuser\\...
C:\\Users\\myuser\\...
But there are something wrong with my code and I can't achieve my objective
#echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
for /r "%USERPROFILE%" %%i in (*) do (
set route=%%i
set route=!route:\=\\!
echo !route!
)
See for /? from the prompt for for /r syntax. Quotes inserted in case of separators in directoryname.
You cannot use a metavariable such as %%i in a string-manipulation command.
Refer to the changed value of a variable with !var! when delayedexpansion has been invoked.
I am trying to get a batch to file read a text file from dropbox and execute it as variables in the batch file.
this is what i am trying, but it does not work, please help!
SetLocal EnableDelayedExpansion
set content=
for /F "delims=" %%i in (DROPBOX-LINK-HERE) do set content=!
content! %%i
%content%
EndLocal
I'm not sure what you mean by DROPBOX-LINK-HERE, but I am using an ordinary text file for content.
You must separate each line with & or else enclose the content in parentheses and separate each line with <linefeed>. The linefeed solution is more complicated, but has fewer limitations on the content.
Any ! characters in the content will be corrupted during expansion of a FOR variable if delayed expansion is enabled. But delayed expansion is needed to preserve unquoted special characters. So delayed expansion needs to be creatively toggled on and off.
Here is code that I think does what you want.
#echo off
setlocal disableDelayedExpansion
::Define a carriage return variable
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
::Create a newline variable
set LF=^
::The above 2 blank lines are critical - do not remove
::Both CR and LF should be expanded using delayed expansion only.
::Load the content into a variable.
::We want to separate lines with linefeed, but FOR /F won't preserve linefeeds.
::So use carriage return as a place holder for now.
set "content=("
setlocal enableDelayedExpansion
for /f %%C in ("!CR! ") do (
endlocal
for /f "delims=" %%A in (test.txt) do (
setlocal enableDelayedExpansion
for /f "delims=" %%B in ("!content!") do (
endlocal
set "content=%%B%%C%%A"
)
)
)
::Now replace carriage returns with newline and append terminating )
setlocal enableDelayedExpansion
for /f %%C in ("!CR! ") do for %%N in ("!LF!") do set "content=!content:%%C=%%~N!%%~N)"
::Execute the content
endlocal&%content%
The code works, but there are limitations to the type of code that can be executed from a variable.
Variables cannot be expanded by using normal expansion unless you use CALL. For example, a line like echo %var% will not work, but call echo %var% will work. Another option is to use delayed expansion. SETLOCAL EnableDelayedExpansion and ENDLOCAL can be included in the content as needed.
You cannot CALL or GOTO a :LABEL within the content.
That's all I can remember at the moment, but there may be (probably are) other restrictions.
I have one question though:
If the content is already in a text file, then why not simply give the text file a .BAT extension and execute it?