This is my precommit hook. When I start a commit, my external diff tool does pops up, but the cmd window shows nothing, and it doesn't read my keyboard input.
@echo off
for /F "usebackq" %%i IN (%1) DO (svn diff %%i >nul)
echo hello
choice /M "Continue to commit?"
SET userChoice=%ERRORLEVEL%
IF %userChoice% equ 1 exit /b 0
IF %userChoice% equ 2 exit /b 1
Did I miss anything?
According to the help documentation of TortoiseSVN you need to do explicit redirection to the console (device con
):
When debugging hook scripts you may want to echo progress lines to the DOS console, or insert a pause to stop the console window disappearing when the script completes. Because I/O is redirected this will not normally work. However you can redirect input and output explicitly to CON to overcome this. eg
echo Checking Status > con pause < con > con
Unfortunately, this does not work with the choice
command as it does not seem to accept input redirected from device con
:
>>> choice < con ERROR: The handle is invalid.
A simple work-around is to use the set /P
command which does support redirection from con
:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Loop structure for prompting user:
:CONFIRM
rem // Display prompt and await user input:
< con > con set /P SELECT="Continue? [Yes/No]?"
rem // Check user input case-insensitively:
if /I "%SELECT%"=="Y" exit /B 0
if /I "%SELECT%"=="Yes" exit /B 0
if /I "%SELECT%"=="N" exit /B 1
if /I "%SELECT%"=="No" exit /B 1
rem // Repeat prompt in case of invalid entry:
goto :CONFIRM
endlocal
exit /B
The disadvantage of this is that the entry needs to be terminated with RETURN , in contrast to the choice
command, which accepts a single-key input.
Here is a better approach which features a single-key prompt similar to the choice
command. This (mis-)uses the xcopy
command and its ability to accept redirected input into the copy confirmation prompt that appears when the /W
switch is supplied. Take also a look at the explanatory remarks:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem // Loop structure for prompting user:
:CONFIRM
rem // Display prompt without trailing line-break:
< nul > con set /P ="Continue? [Y/N]?"
rem /* Let `xcopy` wait for a single-key entry using its `/W` switch;
rem `/L` tells `xcopy` to actually copy nothing; to avoid problems
rem with inexistent paths, use this script's path as source file
rem and the system's temporary directory as the target location: */
< con (
for /F "delims=" %%L in ('
xcopy /L /W "%~f0" "%TMP%\"
') do (
rem /* Capture the copy confirmation prompt of `xcopy /L /W`,
rem `Press any key when ready to begin copying file(s)`,
rem together with the character entered by the user, which
rem is appended to the prompt message: */
set "CHAR=%%L"
rem /* Leave loop upon first iteration, because we are not
rem interested in any copying results and summaries: */
goto :SKIP
)
)
:SKIP
rem // Extract the last character, which is the actual user input:
set "CHAR=!CHAR:~-1!"
rem // Display user entry:
> con echo(!CHAR!
rem // Check user input case-insensitively:
if /I "!CHAR!"=="Y" exit /B 0
if /I "!CHAR!"=="N" exit /B 1
rem // Repeat prompt in case of invalid entry:
goto :CONFIRM
endlocal
exit /B
If an unexpected input is provided, the prompt is reprinted on the next line and new user input is awaited.
To avoid reprinting the prompt text in case of unexpected user input, use the following script:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "MESSAGE=Confirm? [Y/N]?"
rem // Retrieve back-space character:
for /F %%Z in ('prompt $H ^& for %%Z in ^(.^) do rem/') do set "BS=%%Z"
rem // Retrieve carriage-return character:
for /F %%Z in ('copy /Z "%~f0" nul') do set "CR=%%Z"
rem // Loop structure for prompting user:
:CONFIRM
setlocal EnableDelayedExpansion
rem // Display prompt without trailing line-break:
> con < nul set /P ="%BS% !CR!!MESSAGE!"
endlocal
rem /* Let `xcopy` wait for a single-key entry using its `/W` switch;
rem `/L` tells `xcopy` to actually copy nothing; to avoid problems
rem with inexistent paths, use this script's path as source file
rem and the system's temporary directory as the target location: */
< con (
for /F "delims=" %%L in ('
xcopy /L /W "%~f0" "%TMP%\"
') do (
rem /* Capture the copy confirmation prompt of `xcopy /L /W`,
rem `Press any key when ready to begin copying file(s)`,
rem together with the character entered by the user, which
rem is appended to the prompt message: */
set "CHAR=%%L"
rem /* Leave loop upon first iteration, because we are not
rem interested in any copying results and summaries: */
goto :SKIP
)
)
:SKIP
setlocal EnableDelayedExpansion
rem // Extract the last character, which is the actual user input:
set "CHAR=!CHAR:~-1!"
rem // Display user entry without trailing line-break:
> con < nul set /P ="!CHAR!"
rem // Check user input case-insensitively:
if /I "!CHAR!"=="Y" exit /B 0
if /I "!CHAR!"=="N" exit /B 1
endlocal
rem // Repeat prompt in case of invalid entry:
goto :CONFIRM
echo/
endlocal
exit /B
This is a comprehensive solution that allows usage of special characters like !
, ^
and "
too.
Here is a quite similar solution relying on the replace
command, together with its /W
switch, also without reprinting the prompt in case of unexpected user input. Since replace
prints the character of the key-press in a separate line, there is no need to split it off of another string (opposed to xcopy /W
):
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "MESSAGE=Confirm? [Y/N]?"
rem // Retrieve back-space character:
for /F %%Z in ('prompt $H ^& for %%Z in ^(.^) do rem/') do set "BS=%%Z"
rem // Retrieve carriage-return character:
for /F %%Z in ('copy /Z "%~f0" nul') do set "CR=%%Z"
rem // Loop structure for prompting user:
:CONFIRM
setlocal EnableDelayedExpansion
rem // Display prompt without trailing line-break:
> con < nul set /P ="%BS% !CR!!MESSAGE!"
endlocal
rem /* Let `replace` wait for a single-key entry using its `/W` switch;
rem `/U` tells `replace` to actually do nothing; to avoid problems
rem with inexistent paths, use this script's path as source file
rem and its parent directory as the target location: */
< con (
for /F "skip=1 delims=" %%L in ('
replace /W /U "%~f0" "."
') do (
rem /* Capture the confirmation user input of `replace /W /U`,
rem skipping the prompt `Press any key to continue . . .`: */
set "CHAR=%%L"
rem /* Leave loop upon first iteration, because we are not
rem interested in any replacement results and summaries: */
goto :SKIP
)
)
:SKIP
setlocal EnableDelayedExpansion
rem // Display user entry without trailing line-break:
> con < nul set /P ="!CHAR!"
rem // Check user input case-insensitively:
if /I "!CHAR!"=="Y" exit /B 0
if /I "!CHAR!"=="N" exit /B 1
endlocal
rem // Repeat prompt in case of invalid entry:
goto :CONFIRM
echo/
endlocal
exit /B
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.