Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
Here is a hybrid batch/vbscript I wrote to get a browseforfolder dialog when running a batch file. I've tweaked it as much as my current skill allows and it works pretty well as is but I thought I'd throw it up for critiques or improvements/suggestions.
#Echo off
setlocal
Call :BrowseFolder "Choose Source folder" "C:\scripts\batch\"
Set SourceFolder=%Result%
Call :BrowseFolder "Choose Destination folder" "C:\scripts\"
Set DestinationFolder=%Result%
Echo %SourceFolder%
Echo %DestinationFolder%
cmd /k
endlocal
Goto :EOF
:BrowseFolder
set Result=
set vbs="%temp%\_.vbs"
set cmd="%temp%\_.cmd"
for %%f in (%vbs% %cmd%) do if exist %%f del %%f
for %%g in ("vbs cmd") do if defined %%g set %%g=
>%vbs% echo set WshShell=WScript.CreateObject("WScript.Shell")
>>%vbs% echo set shell=WScript.CreateObject("Shell.Application")
>>%vbs% echo set f=shell.BrowseForFolder(0,%1,0,%2)
>>%vbs% echo if typename(f)="Nothing" Then
>>%vbs% echo wscript.echo "set Result=Dialog Cancelled"
>>%vbs% echo WScript.Quit(1)
>>%vbs% echo end if
>>%vbs% echo set fs=f.Items():set fi=fs.Item()
>>%vbs% echo p=fi.Path:wscript.echo "set Result=" ^& p
cscript //nologo %vbs% > %cmd%
for /f "delims=" %%a in (%cmd%) do %%a
for %%f in (%vbs% %cmd%) do if exist %%f del %%f
for %%g in ("vbs cmd") do if defined %%g set %%g=
goto :eof
Here is a similar example of this functionality in Batch/JScript Hybrid
I have not thoroughly tested this, but wanted to give you an example based on my comment. This method does not require any additional temporary files.
#if (#CodeSection == #Batch) #then
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The first line in the script is...
:: in Batch, a valid IF command that does nothing.
:: in JScript, a conditional compilation IF statement that is false.
:: So the following section is omitted until the next "[at]end".
:: Note: the "[at]then" is required for Batch to prevent a syntax error.
:: If the task cannot be done in batch, use PowerShell with fallback J/WScript.
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Batch Section
#echo off
for /f "delims=" %%A in ('CScript //E:JScript //Nologo "%~f0" FolderBox "Hello Temp" "%Temp%"') do echo %%A
pause
exit /b 0
:: End of Batch
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#end
////////////////////////////////////////////////////////////////////////////////
// JScript Section
try
{
switch(WScript.Arguments.Item(0))
{
case 'FolderBox':
{
var Title = WScript.Arguments.Item(1);
var StartPath = WScript.Arguments.Item(2);
var Shell = WScript.CreateObject('Shell.Application');
var Result = Shell.BrowseForFolder(0, Title, 0, StartPath);
if (Result != null)
{
var Items = Result.Items();
if (Items != null)
{
for (var i = 0; i < Items.Count; i++)
{
WScript.Echo(Items.Item(i).Path);
}
WScript.Quit(0);
}
}
WScript.Quit(1);
}
break;
default:
{
WScript.Echo('Invalid Command: ' + WScript.Arguments.Item(0));
}
break;
}
}
catch(e)
{
WScript.Echo(e);
WScript.Quit(1);
}
WScript.Quit(0);
Related
I have a batch function and I need to return a value from it. Following is the script:
#echo off
call :Mode mode1
echo mode is %mode1%
:Mode
setlocal enabledelayedexpansion
set count=0
for /f "tokens=*" %%x in (map.txt) do (
set /a count+=1
set var[!count!]=%%x
)
for /f "tokens=2 delims=: " %%A in ("%var[2]%") Do (
set mode=OPEN
)
IF %mode%==OPEN (
echo coming into open
set %1=OPEN
echo %mode1%
) ELSE (
echo coming into shorted
set %1=SHORTED
echo %mode1%
)
EXIT /B 0
echo mode is %mode1% doesn't print anything. Any help? I've hardcoded set mode=OPEN for testing purposes.
Each exit, exit /b or goto :eof implicitly does an endlocal, so you need a trick for your variable %1 to survive an endlocal. endlocal & set ... & goto :eof does the trick because the whole line gets parsed in one go:
#echo off
call :Mode mode1
echo mode is %mode1%
goto :eof
:Mode
setlocal enabledelayedexpansion
set "mode=OPEN"
IF "%mode%" == "OPEN" (
echo coming into open
endlocal&set "%1=OPEN"&goto :eof
) ELSE (
echo coming into shorted
endlocal&set "%1=SHORTED"&goto :eof
)
For the same reason, echo %mode1% in your subroutine does not print the variable.
Note: I changed set and if syntax to recommended quoted syntax.
Trying to isolate just a portion of a string contained in a .BAT variable.
The String Variable !Original! contains the following:
v2.30|Action=Allow|Active=FALSE|Dir=In|Profile=Domain|Profile=Private|Name=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/PackageDisplayName}|Desc=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/ProductDescription}|LUOwn=S-1-5-21-1502285707-838241421-2811185785-1001|AppPkgId=S-1-15-2-1861897761-1695161497-2927542615-642690995-327840285-2659745135-2630312742|EmbedCtxt=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/PackageDisplayName}|Platform=2:6:2|Platform2=GTEQ|
I'm trying to parse it for the sequence of characters just after the word "Name=".
The following For Loop returns: The system cannot find the file v2.30|Action.
FOR /F "tokens=* delims=" %%h in (!Original! ^| Findstr "Name=") do (ECHO %%h)
What am I doing wrong? Why does it only read the first little part of the contents of !Original! ?
Appreciated...
Try this (save it as a .bat):
#if (#X)==(#Y) #end /* JScript comment
#echo off
set "string=v2.30|Action=Allow|Active=FALSE|Dir=In|Profile=Domain|Profile=Private|Name=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/PackageDisplayName}|Desc=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/ProductDescription}|LUOwn=S-1-5-21-1502285707-838241421-2811185785-1001|AppPkgId=S-1-15-2-1861897761-1695161497-2927542615-642690995-327840285-2659745135-2630312742|EmbedCtxt=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/PackageDisplayName}|Platform=2:6:2|Platform2=GTEQ|"
set "splitBy=|"
for /f "tokens=* delims=" %%a in ('cscript //E:JScript //nologo "%~f0" "%string%" "%splitBy%"') do (
set "%%~a" 2>nul
)
echo %Name%
exit /b %errorlevel%
#if (#X)==(#Y) #end JScript comment */
var string=WScript.Arguments.Item(0);
var splitBy=WScript.Arguments.Item(1);
var i;
for (i = 0; i < string.split(splitBy).length; i++) {
WScript.Echo(string.split(splitBy)[i]);
}
batch syntax only solution:
#echo off
setlocal EnableDelayedExpansion
#echo off
REM Creating a Newline variable (the two blank lines are required!)
set NLM=^
set NL=^^^%NLM%%NLM%^%NLM%%NLM%
set "string=v2.30|Action=Allow|Active=FALSE|Dir=In|Profile=Domain|Profile=Private|Name=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/PackageDisplayName}|Desc=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/ProductDescription}|LUOwn=S-1-5-21-1502285707-838241421-2811185785-1001|AppPkgId=S-1-15-2-1861897761-1695161497-2927542615-642690995-327840285-2659745135-2630312742|EmbedCtxt=#{Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy?ms-resource://Microsoft.Windows.Cortana/resources/PackageDisplayName}|Platform=2:6:2|Platform2=GTEQ|"
setlocal enableDelayedExpansion
echo !string:^|=%NL%! >#
for /f "tokens=* delims=" %%a in (#) do (
set "%%~a" >nul 2>&1
)
echo %NAME%
del /q #
Is there way to echo text after a set command? I have tried, but nothing seems to work. Here is my code:
#echo off
Echo Enter a website:
Set /p op="Https:\\" ".com"
:: The ".com" would be displayed behind the users input.
if %op%==%op% goto Show
:Show
cls
Echo Website: Http:\\%op%.com
pause
exit
How would I get the .com to be displayed after the input? I would preferably like to have the ".com" frozen in one spot, no matter how big the users input is.
I took the solution from this answer and slightly modified it in order to fulfill this request.
#echo off
setlocal EnableDelayedExpansion
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set "op="
set /P "=Https:\\.com!BS!!BS!!BS!!BS!" < NUL
:nextKey
set "key="
for /F "delims=" %%K in ('xcopy /W "%~F0" "%~F0" 2^>NUL') do if not defined key set "key=%%K" & set "key=!key:~-1!"
if "!key!" equ "!CR!" goto endInput
if "!key!" neq "!BS!" (
set "op=%op%%key%"
set /P "=.!BS!%key%.com!BS!!BS!!BS!!BS!" < NUL
) else if defined op (
set "op=%op:~0,-1%"
set /P "=.!BS!!BS!.com !BS!!BS!!BS!!BS!!BS!" < NUL
)
goto nextKey
:endInput
echo/
echo/
echo Website: Http:\\%op%.com
EDIT: New method added (requested in a comment)
#echo off
setlocal EnableDelayedExpansion
set /A spaces=10, backSpaces=spaces+4
set "spcs="
for /L %%i in (1,1,%spaces%) do set "spcs=!spcs! "
set "back="
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /L %%i in (1,1,%backSpaces%) do set "back=!back!!BS!"
set /P "op=Https:\\%spcs%.com!back!"
echo/
echo Website: Http:\\%op%.com
Per #Marged's comments, I suspect this is impossible (or at least extremely difficult) by batch file.
Here's a PowerShell solution should that be of use:
function Get-UserInput {
param (
[parameter(mandatory = $false)]
[string]$pre='Enter text:'
,
[parameter(mandatory = $false)]
[string]$post='_'
)
process {
[string]$text=''
while ($key.Key -ne 'Enter') {
write-host "`r$pre$text$post " -NoNewline #trailing space to hide deleted chars
#replace the above with the 3 below if you want user input to be a different colour to the defaults
#write-host "`r$pre" -NoNewline
#write-host $text -NoNewline -ForegroundColor Cyan
#write-host "$post " -NoNewline #trailing space to hide deleted chars
$key = [Console]::ReadKey($true)
switch ($key.Key)
{
'Backspace' { $text = $text.substring(0,($text.length-1)) }
default { $text = $text + $key.KeyChar }
}
}
write-host "" #undo no new line
write-output "$pre$text$post"
}
}
clear-host
$input = Get-UserInput -pre 'https://' -post '.com'
"User entered: '$input'"
I have file:
<tag1>text1</tag1><tag2>text2</tag2>
<tag3>text3</tag3>
I want to be :
text1
text2
text3
with new line for every text.Is it possible with batch?
#ECHO OFF
SETLOCAL
(
FOR /f "delims=" %%a IN (q28433530.txt) DO (
SET "line=%%a"
CALL :process
)
)>newfile.txt
GOTO :EOF
:process
:procloop
FOR /f "tokens=1,2,3*delims=<>" %%i IN ("%line%") DO IF "%%j" neq "" ECHO(%%j&IF "%%l" neq "" SET "line=%%l"&GOTO procloop
GOTO :EOF
I used a file named q28433530.txt containing your data for my testing.
Produces newfile.txt
This would probably do what you appear to want, provied you've given us realistic representative data.
You could evaluate the file as XML and output each leaf node's nodeValue.
#if (#CodeSection == #Batch) #then
#echo off
setlocal
set "xmlfile=test.xml"
#cscript /nologo /e:JScript "%~f0" "%xmlfile%" & goto :EOF
#end
var xmlDoc = WSH.CreateObject('Microsoft.XMLDOM'),
fso = WSH.CreateObject('scripting.filesystemobject'),
xmlFile = fso.OpenTextFile(WSH.Arguments(0), 1);
xmlDoc.loadXML('<root>' + xmlFile.ReadAll() + '</root>');
xmlFile.Close();
xmlDoc.async = false;
if (xmlDoc.parseError.errorCode) {
var myErr = xmlDoc.parseError;
WSH.Echo(myErr.reason);
} else {
function walker(node) {
for (var nodes=node.childNodes, i=0; i<nodes.length; i++) {
if (nodes[i].hasChildNodes) {
walker(nodes[i]);
} else {
WSH.Echo(nodes[i].nodeValue);
}
}
}
walker(xmlDoc.documentElement);
}
In Linux (Bash) there is a very useful functionality for dumping literal text out to another file like this:
cat > see.txt << EOF
contents going into
my file
EOF
What I need is the equivalent for a Windows batch script. I haven't found this kind of functionality built-in, but I was thinking I could write a subroutine to do it (I don't want to rely on anything that isn't natively in Windows since XP), but I'm having trouble. Here's what I have so far with help from various sources:
call:catMyChunk myCustomText c:\see.txt
exit /b
goto:myCustomText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:myCustomText
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
set startLine=0
set endLine=0
for /f "delims=:" %%a in ('findstr -b -n !searchStart! %~dpnx0') do set "startLine=%%a"
for /f "delims=:" %%a in ('findstr -b -n !searchStop! %~dpnx0') do set "endLine=%%a"
set /a linesLeftToRead=%endLine% - %startLine%
del %outFile%
if "%linesLeftToRead%" LEQ "0" (
echo Error finding start and end delmieters for %searchStop% in catMyChunk routine
exit /B 1
)
setlocal DisableDelayedExpansion
for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
set "oneLine=!oneLine:*:=!"
set /a linesLeftToRead-=1
if !linesLeftToRead! LEQ 0 exit /B
echo(!oneLine!>>%outFile%
)
goto: EOF
So my requirement is that the chunk of text is output literally without any changes whatsoever (i.e. I don't want to have to escape blank lines, %, !, <, etc.). This code is doing almost everything I need, except I haven't found a way to get the exclamation points output properly. Here is the output I get, which isn't quite right:
This is my test file
Hope you like it.
<got these>
% and these %
these too
yeah
Edit:
For anyone wanting the modified version of the subroutine that now works, here it is:
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
set startLine=0
set endLine=0
for /f "delims=:" %%a in ('findstr -b -n !searchStart! %~dpnx0') do set "startLine=%%a"
for /f "delims=:" %%a in ('findstr -b -n !searchStop! %~dpnx0') do set "endLine=%%a"
set /a linesLeftToRead=%endLine% - %startLine%
del %outFile%
if "%linesLeftToRead%" LEQ "0" (
echo Error finding start and end delmieters for %searchStop% in catMyChunk routine
exit /B 1
)
setlocal DisableDelayedExpansion
for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
set "oneLine=%%a"
set /a linesLeftToRead-=1
setlocal EnableDelayedExpansion
set "oneLine=!oneLine:*:=!"
if !linesLeftToRead! LEQ 0 exit /B
echo(!oneLine!>>%outFile%
endlocal
)
endlocal
goto: EOF
Your code is missing a single endlocal in your FOR-loop.
You will then create for each loop a new local-context through the setlocal EnableDelayedExpansion, this will explode with some more lines in your text file.
Also, to preserve the exclamation marks (and also the carets) you need the toggling technique:
DOS batch files: How to read a file?
setlocal DisableDelayedExpansion
for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
set "oneLine=!oneLine:*:=!"
set /a linesLeftToRead-=1
if !linesLeftToRead! LEQ 0 exit /B
echo(!oneLine!>>%outFile%
endlocal
)
+1, Interesting application! I modified your code for a simpler and faster version:
#echo off
call :catMyChunk myCustomText see.txt
exit /b
goto:myCustomText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:myCustomText
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
setlocal DisableDelayedExpansion
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
if exist %outFile% del %outFile%
set copyFlag=No
echo No> copyFlag
for /f "delims=" %%a in (%~f0) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
if !copyFlag! == No (
if !oneLine! == %searchStart% echo Yes> copyFlag
) else (
if !oneLine! == %searchStop% (
echo No> copyFlag
) else (
echo/!oneLine!>> %outFile%
)
)
endlocal
set /p copyFlag=< copyFlag
)
endlocal
goto :eof
I also created another version that looks more like the Linux version, that is, the lines to copy are placed directly after invoking the routine, and the execution continue after the last copied line. Of course, to make this possible the routine is not invoked via call, but entered with a goto, and when the routine ends it execute a goto %MYDELIM% instead of a "return" (exit /b or goto :eof). Also, because a goto can not have parameters, the "parameters" are defined in variables before the invocation.
#echo off
set searchStop=EndOfMyText
set outFile=see.txt
goto :catMyChunk EndOfMyText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:EndOfMyText
exit /b
:catMyChunk
::Before JUMP to this "function" define 2 vars: searchStop and outFile
::where is to be catted to %outFile%
::and text starts with goto :catMyChunk %searchStop%
::and ends with :%searchStop%
setlocal DisableDelayedExpansion
set searchStart=goto :catMyChunk %searchStop%
if exist %outFile% del %outFile%
set copyFlag=No
echo No> copyFlag
for /f "delims=" %%a in (%~f0) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
if !copyFlag! == No (
if /I !oneLine! == !searchStart! echo Yes> copyFlag
) else (
if !oneLine! == :%searchStop% (
echo No> copyFlag
) else (
echo/!oneLine!>> %outFile%
)
)
endlocal
set /p copyFlag=< copyFlag
)
endlocal
goto %searchStop%
EDIT
This new version is even faster and now works with all special cases, including empty lines:
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
setlocal EnableDelayedExpansion
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
if exist %outFile% del %outFile%
findstr /n ^^ "%~f0" > pipeline.txt
call :seekMyChunk < pipeline.txt
del pipeline.txt
exit /B
:seekMyChunk
set oneLine=:EOF
set /P oneLine=
if !oneLine! == :EOF goto startNotFound
set oneLine=!oneLine:*:=!
if not !oneLine! == %searchStart% goto seekMyChunk
:catNextLine
set oneLine=:EOF
set /P oneLine=
if !oneLine! == :EOF goto stopNotFound
set oneLine=!oneLine:*:=!
if !oneLine! == %searchStop% goto :eof
echo/!oneLine!>> %outFile%
goto catNextLine
:startNotFound
echo Error finding start delimiter for %searchStart% in catMyChunk
goto :eof
:stopNotFound
echo Error finding stop delimiter for %searchStop% in catMyChunk
goto :eof