set var=C:\Users\user\Desktop\bla\bla.exe
set var=%var:*\%
echo %var%
this returns Users\user\Desktop\bla\bla.exe - is there any way to make it focus on the last \ and not the first one so that it would just return bla.exe? bear in mind that this will be used on multiple files and folders so i won't always know how many sub-folders there are.
#ECHO OFF
SETLOCAL
set "var=C:\Users\user\Desktop\blah blah\bla.exe"
FOR %%a IN ("%var%") DO (
SET "filename=%%~nxa"
FOR %%b in ("%%~dpa.") DO SET "lastleaf=%%~nxb"
)
ECHO filename is "%filename%"
ECHO lastleaf is "%lastleaf%"
GOTO :EOF
Normally, the next question is about how to obtain the last leaf of the directory-tree. No subroutines required...
Note positioning of quotes to minimise problems with separators. ALso minor directory name-change to exhibit differences.
The following snippet shows one way to do it.
#setlocal enableextensions enabledelayedexpansion
#echo off
:main
set var=C:\Users\user\Desktop\blah blah\yada yada.exe
call :basename result "%var%"
echo %result%
endlocal
goto :eof
:basename
set %1=%~nx2
goto :eof
It basically calls a function basename (named after the UNIX utility), passing the full name and the variable you want to assign the base name to, and you need to make sure you quote it properly lest filenames containing spaces will cause you problems.
The full set of variable modifiers can be seen in the call /? help output.
Alternatively, you can use the same basename functionality in a one-liner for statement:
for /f "delims=" %%I in ("%var%") do set result=%%~nxI
This allows you to get the base name without having to call a function. I tend to prefer the function myself since it's more readable but you could probably alleviate that by just including a comment:
rem Get base name of var into result:
rem eg: var = C:\Users\user\Desktop\blah blah\yada yada.exe
rem result = yada yada.exe
for /f "delims=" %%I in ("%var%") do set result=%%~nxI
Related
I have a file C:\parameters.txt that contains different parameters, for example:
env_user=username123
env_pw=password123
env_url=example.com
Now I created a .cmd file that needs to get these values and put them in a variable, for example:
SET var_user=<Here I need 'username123'>
SET var_pw=<Here I need 'password123'>
SET var_url=<Here I need 'example.com'>
How do I write this in my cmd script to get the correct values for my variables?
You need to set a delimiter for = character so that words before/after = will be separated. Besides that, you need an array to set each of the parameters. You can do it like this:
#echo off
setlocal enabledelayedexpansion
set increment=0
for /f "tokens=1* delims==" %%a in (C:\parameters.txt) do (
set parameters_array[!increment!]=%%b
set /a increment+=1
)
echo %parameters_array[0]%
echo %parameters_array[1]%
echo %parameters_array[2]%
pause >nul
Keep in mind, array always starts from 0. You could change to set increment=1 if you prefer the array starts from 1.
Just a slight alternative to dark fang's solution, since your parameters.txt file's contents are already in the format of variable=value, you could
#echo off
setlocal
for /f "usebackq delims=" %%I in ("c:\parameters.txt") do set "%%I"
rem // display env_* variables
set env_
pause
The usebackq option allows you to quote the file name, which might be needed if you ever move c:\parameters.txt to a location containing spaces, ampersands, or other tricksy characters. It's a good habit to follow when reading the contents of text files with for /f.
Also, it's better not to use delayed expansion if you don't need it, as delayed expansion can sometimes corrupt values containing exclamation marks -- a situation that is reasonably possible when dealing with passwords.
I've found the solution thanks to different inputs.
#echo off
For /F "tokens=1* delims==" %%A IN (C:\parameters.txt) DO (
IF "%%A"=="env_user" set var_user=%%B
IF "%%A"=="env_pw" set var_pw=%%B
IF "%%A"=="env_url" set var_url=%%B
)
This will set the correct variables (not local) once the specific code name (before the = in parameters.txt) has been found.
I'm trying to do this, but my "v" variable is !expanded!. Augh. I've tried flipping things around but I'm not very good with expansion. How could I adjust the map and lookup to work with an expanded variable?
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
set map=mon;Monday;tue;Tuesday;wed;Wednesday;thu;Thursday;fri;Friday;sat;Saturday;sun;Sunday
FOR /f "delims=" %%i IN (q20764599.txt) DO (
SET "v=%%i"
CALL :setv
ECHO ==!v!==
)
ECHO +%v%+
GOTO :EOF
:setv
CALL SET v=%%map:*%v%;=%%
SET v=%v:;=&rem.%
GOTO :eof
This should simulate your wanting to work with !v!. The file q20764599.txt could contain say a single line reading tue which gets assigned to v and the magic proceeds from there...
There are more than 10 html files with image tags. Every time we deploy our build onto test site we need to change the img source. for eg <img src=/live/Content/xyz.png />
to <img src=/test/Content/xyz.png />.
After looking around and reading for sometime, i have come up with the following batch script, however i cant figure out how do i go further from here :
for /r %%i in (*.html) do echo %%i
for %%f in (*.html) do (
FOR /F %%L IN (%%f) DO (
SET "line=%%L"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "x= <--------------------WHAT DO I SET HERE?
echo %x%
ENDLOCAL )) pause
This is my first batch script, could anyone please guide me in the right direction?
#ECHO OFF
SETLOCAL enabledelayedexpansion
for /r U:\ %%i in (*.html) do (
echo found %%i
SET outfile="%%~dpni.lmth"
(
SETLOCAL disabledelayedexpansion
FOR /F "usebackq delims=" %%L IN ("%%i") DO (
SET "line=%%L"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "line=!line:/live/=/test/!
echo !line!
ENDLOCAL
)
ENDLOCAL
)>!outfile!
)
pause
GOTO :EOF
How about this development?
Notes:
I've modified your FOR/R to ECHO the HTML file being processed and use %%i rather than switching to %%f. U: is my RAMDRIVE; you'd need to modify that to suit.
outfile is set to generate a filename which matches the HTML filename, but with a .lmth extension (can't update in-place) - it gets that from the ~dpn prefixing the i, which means the drive, path and name of the file %%i. It's quoted to take care of potential spaces in the filename or pathname.
The next logical statement is (for /f...[lines] )>!outfile! which sends any echoed text to a NEW file !outfile!. The enabledelayedexpansion in the second physical line of the batch makes !outfile! the RUN-TIME value - as it is changed within the FOR r outer loop.
Since the actual HTML filename in %%i may contain spaces, it needs to be quoted, hence the 'usebackq' clause in the FOR/F. The delims= clause ensures that the ENTIRE line from the file "%%i" is applied to %%L - not just the first token (well, actually, makes the entire line the first token).
The SET command substitutes the string "/test/" for any occurrence of "/live/" in the RUN-TIME value of the variable lineand assigns the result to line. The resultant value is then ECHOd - which is redirected to outfile
Note that in your original, you would be assigning x in the set x= but echo %x% would have reproduced x as it stood when the line was PARSED because batch substitutes the value of any variable for %var% as part of the parsing phase. Consequently, the line would have become simply ECHO (since x would likely be unassigned) and bizarrely would have reported the echo state (Echo is OFF)
A couple of gatchas here. First, % and some other characters are notoriously hard to process with batch, so be careful. Next, FOR/F will bypass empty lines. This can be overcome if required. Third, this will replace ANY occurrence of /live/ in any case with /test/
Good luck!
Edit to support exclamation marks: 20130711T0624Z
Added SETLOCAL enabledelayedexpansion line and ENDLOCAL just before )>!outfile! to match
I am creating an MS DOS batch script that needs to list every .bat file in the current directory, but not show autoexec.bat or other utilities or systems .bat files that shouldn't be run by the user.
I currently have DIR "*.bat" /B /P
This lists all .bat files appropriately, but it shows autoexec.bat. How would I exclude that from the list? Also slightly important, how could I chop off the file extensions and show more than the 7-characters DOS limits files to?
Constraints: I am not able to use a DOS version above WinME. That is the version I am using.
Thanks for any help.
EDIT:
There is plenty of information on the internet about doing this, but it is all in the windows command processor, not MS DOS. Please understand that DOS and the Command Prompt are not the same thing.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
echo %%~Na
)
)
EDIT: Some explanations added
Batch file processing is slow, so you should use techniques that allows a Batch file to run faster. For example:
Try to use the minimum lines/commands to achieve a certain result. Try to avoid external commands (*.exe files) like find, findstr, fc, etc. specially if they work on small amounts of data; use if command instead.
Use for %%a in (*.bat)... instead of for /F %%a in ('dir /B *.bat').... The second method requires to execute cmd.exe and store its output in a file before for command can process its lines.
Avoid pipes and use redirections instead. A pipe require the execution of two copies of cmd.exe to process the command at each side of the pipe.
A simple way to check if a variable contain a given string is trying to delete the string from the variable: if the result is different then the string exists in the variable: if "!variable:%string%=!" neq "%variable%" echo The string is in the variable.
Previous method may also be used to check if a variable have anyone of a list of values: set list=one two three, if "!list:%variable%=!" neq "%list%" echo The variable have one value from the list. If the values of the list may have spaces, they must be separated by another delimiter.
EDIT: New version added as answer to new comments
The easiest way to pause one page at a time is to use more filter this way:
theBatchFile | more
However, the program must reorder the output in order to show it in columns. The new version below achieve both things, so it does not require more filter; you just need to set the desired number of columns and rows per page.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
rem Set the first two next variables as desired:
set /A columns=5, rows=41, wide=(80-columns)/columns, col=0, row=0
rem Create filling spaces to align columns
set spaces=
for /L %%a in (1,1,%wide%) do set spaces= !spaces!
set line=
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
rem If this column is less than the limit...
set /A col+=1
if !col! lss %columns% (
rem ... add it to current line
set name=%%~Na%spaces%
set "line=!line!!name:~0,%wide%! "
) else (
rem ... show current line and reset it
set name=%%~Na
echo !line!!name:~0,%wide%!
set line=
set /a col=0, row+=1
rem If this row is equal to the limit...
if !row! equ %rows% (
rem ...do a pause and reset row
pause
set row=0
)
)
)
)
rem Show last line, if any
if defined line echo %line%
Antonio
attrib +h autoexec.bat
should hide autoexec.bat and it should thus not appear in the list
DIR "*.bat" /B /P | find /v "autoexec" | for %i in (*.bat) do #echo %~ni
Using for to process each file name individually:
setlocal enabledelayedexpansion
for /f %%i in ('dir "*.bat" /b') do (
set system=0
if "%%i"=="autoexec.bat" set system=1
if "%%i"=="somesystem.bat" set system=1
if !system!==0 echo %%i
)
Another method without variables:
for /f %%i in ('dir "*.bat" /b') do call :test %%i
goto continue
:test
if "%1"=="autoexec.bat" goto :eof
if "%1"=="somesystem.bat" goto :eof
echo %1
goto :eof
:continue
For both, you can add new filenames to exclude from the list.
I've got a script that does everything I expect it to do, apart from one line.
I've done similar before, but I can't get this one to work.
The code I've got is here
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
::Set Path to be folder of Sage Files
SET PATH=C:\Welcome\Progs\SitesDataSetups\GeorgeYarmouth
::set date variables
for /f "tokens=1" %%i in ('date /t') do set thedate=%%i
set mm=%thedate:~3,2%
set dd=%thedate:~0,2%
set yyyy=%thedate:~6,4%
::Set T_DAY variable to date in ddmmyy format
set T_DAY=%dd%%mm%%yyyy:~2%
c:
cd\
cd %path%
for /f "usebackq tokens=* delims= " %%P in (`dir sage*.csv /od /b`) do (
set SAGE=%%P
set SAGE2=!SAGE:~0,8!_EDITED
set EODNUM=!SAGE:~4,4!
for /f "tokens=* delims= " %%A in (%%P) do (
echo %EODNUM%
set S=%%A
***This line is the problem***
set S=!S:%T_DAY%=%EODNUM%!
echo.!S! >> %PATH%\TEST\!SAGE2!.csv
)
)
endlocal
I was expecting that is would take each line of the csv file and replace it with itself, except with a string replace of the current date with the variable EODNUM (which it does... only the variable is expanded before it is set, so is nothing)... The delayed expansion should solve this, but I can use this line of code
set S=!S:%T_DAY%=!EODNUM!!
because I think its too many !'s for CMD.
Am I missing something, or is there a better way to code this?? (I'm not a programmer of any kind, and most of the code I write comes from trial and error, and 'borrowing' from other scripts, so this may be a very messy way to do this).
Transfer the the value of !EODNUM! to a FOR variable, and then use your FOR variable as the replace string.
echo !EODNUM!
set "S=%%A"
for /f "delims=" %%E in ("!EODNUM!") do set "S=!S:%T_DAY%=%%E!"
echo.!S!>> %PATH%\TEST\!SAGE2!.csv
By way of explanation...
CMD reads (and does env var substitution), parses, and executes one top-level command at a time.
In your example, it reads the "for /f..." command all at once parsing and performing %var% substitution.
Once this is complete, it then executes the for loop, performing delayed !var! substitution.
Unfortunately, !var! substitution is not a do-substitution-until-none-left. This makes it hard (as in the answerer's solution) to perform the substitution into the !var:src=dst! value.
You will need a way that during execution you can get guaranteed substitution. This requires a for-statement, or something that involves reading and %var% substituting again. One way of doing this is to use the CALL :LABEL form where you can call to a specific label in your .cmd file and have this section do what you want:
...
call :GenS
...
and then:
:GenS
set S=!S:%T_DAY%=%EODNUM%!
goto :eof
BTW: I'm perplexed that you didn't notice the ECHO %EODNUM% not working in the loop as during the reading of the for loop all %var% substitutions are made.