I want to drag & drop a file onto a batch script, which will print/echo some text, then call a long-running (exited with Ctrl-C) command-line executable that prints to stdout, with the dropped file as argument, in a cmd.exe window; when Ctrl-C is pressed, the executable should exit, but the cmd.exe should pause
, showing "Press any key to continue" - and when "any key" is pressed, the started cmd.exe finally exits, and its window gets closed. However,
- This should work in a network drive (UNC path) folder - so we must
pushd
at start to mount, andpopd
at end to unmount ( How to run batch file from network share without "UNC path are not supported" message? ) - I want to fix the position of this cmd.exe window, which means executable must be started with
start "A Window Title" cmd /k ...
( Size batch windows and set in specific location ) - I guess, because the window must have a custom unique title, so Windows knows to let go of automatically positioning it, and remember manual size/position for it - I want only one batch file, not two or more calling each other; and I want only one cmd.exe terminal window
Here is my attempt at a reproducible example/test case: let's say we're in C:\tmp\test_bat
(easier to reproduce than network path, but let's imagine we're at network path regardless).
As the input file to drag&drop, let's have mytest.txt
:
Hello world!
Lorem ipsum dolor sit amet ...
Can't think of anything else, really ...
To demonstate a long-running command line program that needs to be interrupted with Ctrl-C, we could have used C:\Windows\System32\PING.EXE
called with arguments like (say) -t yahoo.com
- except there is no meaningful input file there, so drag&drop cannot be really demonstrated with it.
So instead, let's compile the following (extremely simple, no proper checks) C program, text_looper.c
... :
#include <stdio.h>
#include <time.h>
#ifdef _WIN32 // https://stackoverflow.com/q/14818084
#include <Windows.h>
#else
#include <unistd.h>
#endif
void do_sleep(unsigned int sleep_time_ms) {
#ifdef _WIN32
Sleep(sleep_time_ms);
#else
usleep(sleep_time_ms*1000);
#endif
}
#define BUFSIZE 1000
char buff[BUFSIZE];
char *line_read = NULL;
int main(int argc, char *argv[]) {
char* input_file = argv[1];
FILE* file_ptr = fopen(input_file, "r");
printf("Got file: '%s' ; looping... (exit with Ctrl-C)\n\n", input_file);
unsigned int loop_counter = 1;
while( 1 ) { // infinite loop
while( line_read = fgets(buff, sizeof(buff), file_ptr) ) {
// trim newline
line_read[strcspn(line_read, "\r\n")] = 0;
// only carriage return, so left-pad counter, right-pad line
printf("\r%10d: %-50s", loop_counter, line_read);
fflush( stdout );
loop_counter++;
do_sleep(250);
}
fseek(file_ptr, 0, SEEK_SET);
printf("\r%-62s", "(again ...)");
do_sleep(250);
}
fclose(file_ptr);
}
... as per Walkthrough: Compile a C program on the command line | Microsoft Learn: so open a Developer Command Prompt, and run:
cd C:\tmp\test_bat
cl text_looper.c
... and we obtain text_looper.exe
(for a quick test: text_looper.exe mytest.txt
).
This is as far as I got with a batch file call_text_looper.bat
:
@echo off
set "LOOPER_EXE=C:\tmp\test_bat\text_looper.exe"
set "INPUT_FILE=%~1"
for /F %%i in ("%LOOPER_EXE%") do set "EXE_BASENAME=%%~ni"
echo.
echo Creating temporary drive with this .bat file location, and changing current working dir there ...
pushd %~dp0
echo.
echo CWD IS %cd% ; (path to batch dir) is %~dp0
echo.
echo Program: %EXE_BASENAME% (%LOOPER_EXE%) ..
echo Using %INPUT_FILE% as input for program ..
echo.
set "WINDOW_TITLE=call: %EXE_BASENAME%"
start "%WINDOW_TITLE%" cmd /k "%LOOPER_EXE% %INPUT_FILE%"
echo Removing temporary drive ...
popd
echo. & pause
The problem with this call_text_looper.bat
is, that:
- I get two cmd.exe windows opened - one for the
.bat
itself, one for the resulting child cmd.exe process (the "subshell", if you will)- When I press Ctrl-C in the "subshell" window, program exits -- but then I get
cmd.exe
prompt, I do not getpause
with "Press any key to continue" that would close the window ... So I have to close that window manually (the parent.bat
window exits upon "Press any key to continue" as expected)
- When I press Ctrl-C in the "subshell" window, program exits -- but then I get
- once we call with
start ...
, the "subshell" gets started "in parallel"/non-blocking, and thestart ...
command returns immediately, and we proceed directly to "Removing temporary drive"; so:- if you test this batch script in
C:\tmp\test_bat
, it will at least run the program in the "subshell" window because you're on a local drive; but - if you try it from a network location, you will get something like:
... because the temporary drive got unmounted by the parentThe current directory is invalid. V:\path\to\test_bat>
.bat
script, by the time the "subshell" got to use it. - if you test this batch script in
So, how can I get a .batch script that will call the program with argument as per my reqiurements above?
(PS: I thought of defining the preamble (the starting part with echoes and drive mounting) as a function, and have the "subshell" call it instead - but this is BATCH, there are no "functions" here, only labels that you can JUMP to ( https://superuser.com/questions/651936/batch-file-function-is-executed-without-being-called ) - and the child process/"subshell" expectedly does not inherit these labels).