0

I'm getting mad trying to get an editable input in a BAT script, similar to read -i in bash.

I saw all sort of workarounds but I found them too complicated or long or dependant of other files/non-native resources.

Is there any way to use powershell inside the bat in order to emulate an input with editable default string?

I found that this can be called from within a bat:

 powershell -Command "$input = read-host 'Enter Input: '"
Whimusical
  • 6,401
  • 11
  • 62
  • 105

3 Answers3

2
set /p INPUTSTRING=Enter Input:

Note that this does not let you edit a pre-existing variable. To do that requires a different program. My own program editv32.exe/editv64.exe lets you do this:

set INPUTSTRING=Test string
editv32 -p "Enter input: " INPUTSTRING

This will present the "Enter input:" prompt following by the existing content of the INPUTSTRING variable, which you can edit.

Download is here: http://www.westmesatech.com/editv.html

Unrestricted copyrighted freeware.

Bill_Stewart
  • 22,916
  • 4
  • 51
  • 62
  • 1
    Then do `Set /p INPUTSTRING=Enter Input (Default: whatever): ` and on the next line do an `If [%INPUTSTRING%]=[] Set INPUTSTRING=whatever` – TheMadTechnician May 12 '14 at 22:40
  • @Bill Stewart: Please add some explanation of your proposed solution and what the questioner was missing or doing wrong. – Our Man in Bananas May 12 '14 at 22:46
  • `editv32.exe` program _modify_ the value of INPUTSTRING variable in cmd.exe environment? If the new value have different lenght of previous one, it move the rest of environment variables accordingly? Excuse me, but I don't understand how this program works. BTW, the editv.html link not works... – Aacini May 13 '14 at 04:37
  • Sorry, I corrected the URL. Yes, editv32.exe/editv64.exe allow you to edit the content of an environment variable. It even has a -m parameter to mask the input (note that this only displays `*` characters on the screen as you type; the masked input is still stored in plain text in the environment. As such, `-m` is merely a convenience and should not be considered secure). – Bill_Stewart May 13 '14 at 13:20
  • My `editv32`/`editv64`/`readline.exe` utilities have been superseded by my open-source [`editenv`](https://github.com/Bill-Stewart/editenv) utility. – Bill_Stewart Jul 16 '20 at 16:22
1

The solution below is a Batch-JScript hybrid script that uses SendKeys in order to fill the command-line input buffer with the default value, so the user may use the standard edition keys to edit it when the set /P command is executed. However, this method have the inconvenience that the filling of the buffer will always appear in the screen, so it must be cleared before the user enter the data. I am working trying to solve this point.

EDIT: After read MC ND's answer I realized that it is not necessary to prefill the input buffer before the actual input, because characters just entered may also be edited in the same way; this point leads to a much simpler solution.

The method below just prefill the input with an editable string; it does not try to modify the original set /P command behavior in any way.

@if (@CodeSection == @Batch) @then

@echo off
rem Enter the prefill value
CScript //nologo //E:JScript "%~F0" "Prefill value"
rem Read the variable
set /P "var=Prompt: "
echo var=%var%
goto :EOF

@end

WScript.CreateObject("WScript.Shell").SendKeys(WScript.Arguments(0));

For further details, see this post.

Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • That's the best answer so far, as it works out-of-the-box in windows. I am wondering if powershell could be used for a simpler approach, if not that would be the accepted answer – Whimusical May 13 '14 at 07:44
  • I've taken your code and changed it trying to "solve" what you think it is a problematic point. Answer added. Hope this works. – MC ND May 13 '14 at 08:13
  • 2
    Just a note that I don't recommend the SendKeys method in a production environment because you can't guarantee which foreground window has focus. There may be odd edge cases where this does not behave as expected. – Bill_Stewart May 13 '14 at 13:27
0

Following the original idea from Aacini. I've not tested it under all the posible scenarios, but seems to work.

EDITED - Code updated to detect Ctrl+C key press while editing the line. Call to the subroutine returns error level to signal it.

@if (@this == @isBatch) @then
@echo off

    setlocal enableextensions

    call :prefilledSet/P data "Edit this:" "This is the data that must be edited"
    if not errorlevel 1 (
        echo(Data retrieved: [%data%]
    ) else (
        echo(
        echo( ---- Input has been canceled
    )

    endlocal
    exit /B

:prefilledSet/P variable "Prompt" "Prefill value"
    setlocal enableextensions disabledelayedexpansion
    set "line=" 
    <nul set /p "v=%~2"
    for /f "delims=" %%a in ('cscript //nologo //e:jscript "%~f0" "%~3"'
    ) do if not defined line ( set "line=%%a" & set "exitCode=0"
    ) else if "%%a"=="ERROR" ( set "line="    & set "exitCode=1" )
    endlocal & set "%~1=%line%" & exit /b %exitCode%

@end
    WScript.CreateObject("WScript.Shell").SendKeys(WScript.Arguments(0));
    try { 
        WScript.StdOut.WriteLine( WScript.StdIn.ReadLine() );
    } catch (e) { 
        WScript.StdOut.WriteLine('ERROR\r\nERROR'); WScript.Quit(1) 
    };

EDITED - Just to add another option. But sorry, not directly batch code. If you have the option to compile a simple tool (tested with mingw gcc compiler), this c code

#define  _WIN32_WINNT 0x0500
#include "windows.h"

int main(int argc, char **argv){

    HWND hWnd = NULL;
    int  i;

    if (argc < 2) return 1 ;
    hWnd = GetConsoleWindow();

    for (i=0;i<strlen(argv[1]);i++){ 
        PostMessage(hWnd, WM_CHAR, argv[1][i], 0);
    };

    return 0;
}

when compiled will generate a command line tool that will send the text given as first argument to the current console. So, it can be used as (ex. compiled as typetext.exe)

typetext.exe "this is the text to edit" & set /p "var=edit this text:"

As the text is directly sent to the console in where the tool is running, there is no interference with other window being active while this executes.

MC ND
  • 69,615
  • 8
  • 84
  • 126