La modifica di un file batch quando la sua esecuzione

Sono in esecuzione di un file batch. Ora mi rendo conto che devo aggiungere un po di più i comandi alla fine del file batch (modifiche all’esistente contenuto, solo alcuni comandi aggiuntivi). È possibile fare questo, dato che la maggior parte dei file batch vengono letti in modo incrementale ed eseguito uno per uno? O il sistema di leggere l’intero contenuto del file e quindi viene eseguito il lavoro?

  • Devi amare COSÌ veloci risposte. È già iniziato l’esecuzione del batch > inviato una domanda > ho una risposta > modificato il file prima dell’esecuzione completata!
  • Nota anche che quando il file batch viene rimosso o rinominato, il momento dell’istruzione corrente è finito un errore: “Il file batch non può essere trovato.”



6 Replies
  1. 34

    Ho appena provato, e contro la mia intuizione, lo raccolse i nuovi comandi alla fine (su Windows XP)

    Ho creato un file batch contenente

    echo Hello
    pause
    echo world
    

    Ho eseguito il file, e mentre è in pausa, ha aggiunto

    echo Salute
    

    Salvato e premuto invio per proseguire la pausa, tutti e tre i prompt sono stati ripresi per la console.

    Quindi, andare per esso!

  2. 23

    L’interprete dei comandi ricorda la linea di posizione è in un file batch. Come lungo come si modifica il file batch dopo che la corrente è in esecuzione line ti troverai bene.

    Se si modifica prima di allora inizia a fare cose strane (ripetizione di comandi, ecc..).

    • È che documentato, per favore, o è questo dalla vostra esperienza?
    • Questo è vero nella mia esperienza.
    • In realtà, quello che farà è il parser puntatore rimarrà lo stesso indice nel file, in modo che l’aggiunta/rimozione di un testo prima che l’indice shift cosa c’è sotto il puntatore all’istruzione. Cose strane accadere, anzi.
    • Caso in questione – una vita reale funky bug cause facendo questo.
  3. 8

    jeb esempio è un sacco di divertimento, ma è molto dipendente dalla lunghezza del testo che viene aggiunto o eliminato. Penso che la contro-intuitivo, i risultati sono quello sfogo intendeva quando ha detto “Se si modifica prima di allora inizia a fare cose strane (ripetizione di comandi ecc..)”.

    Ho modificato jeb codice per mostrare come la dinamica di codice di lunghezza variabile che può essere liberamente modificato all’inizio di un’esecuzione di file batch come appropriate imbottitura è a posto. Tutta la dinamica sezione è interamente sostituito con ogni iterazione. Ogni linea dinamica è preceduto da non interferire ;. Questo è utile perché permette FOR /F a striscia la dinamica del codice per l’implicita EOL=; opzione.

    Invece di cercare un particolare numero di riga, mi aspetto un commento specifico per individuare il punto in cui il codice dinamico inizia. Questo è più facile da mantenere.

    Io uso linee di uguale segni di innocuo riquadro il codice per consentire l’espansione e la contrazione. Qualsiasi combinazione dei seguenti caratteri può essere utilizzato: virgola, punto e virgola, uguale, spazio, tab e/o di nuova riga. (Naturalmente l’imbottitura non può iniziare con un punto e virgola.) I segni di uguale tra parentesi consentire l’espansione del codice. I segni di uguale dopo la parentesi consentire codice contrazione.

    Nota che FOR /F strisce di righe vuote. Questa limitazione può essere superata utilizzando FINDSTR per il prefisso di ogni riga con il numero di riga e quindi rimuovere il prefisso all’interno del loop. Ma il codice aggiuntivo rallenta cose, quindi non vale la pena di fare, a meno che il codice è dipendente dalle righe vuote.

    @echo off
    setlocal DisableDelayedExpansion
    echo The starting filesize is %~z0
    :loop
    echo ----------------------
    ::*** Start of dynamic code ***
    ;set value=1
    ::*** End of dynamic code ***
    echo The current value=%value%
    ::
    ::The 2 lines of equal signs amount to 164 bytes, including end of line chars.
    ::Putting the lines both within and after the parentheses allows for expansion
    ::or contraction by up to 164 bytes within the dynamic section of code.
    (
      call :changeBatch
      ==============================================================================
      ==============================================================================
    )
    ================================================================================
    ================================================================================
    set /p "quit=Enter Q to quit, anything else to continue: "
    if /i "%quit%"=="Q" exit /b
    goto :loop
    :changeBatch
    (
      for /f "usebackq delims=" %%a in ("%~f0") do (
        echo %%a
        if "%%a"=="::*** Start of dynamic code ***" (
          setlocal enableDelayedExpansion
          set /a newValue=value+1, extra=!random!%%9
          echo ;set value=!newValue!
          for /l %%n in (1 1 !extra!) do echo ;echo extra line %%n
          endlocal
        )
      )
    ) >"%~f0.tmp"
    ::
    ::The 2 lines of equal signs amount to 164 bytes, including end of line chars.
    ::Putting the lines both within and after the parentheses allows for expansion
    ::or contraction by up to 164 bytes within the dynamic section of code.
    (
      move /y "%~f0.tmp" "%~f0" > nul
      ==============================================================================
      ==============================================================================
    )
    ================================================================================
    ================================================================================
    echo The new filesize is %~z0
    exit /b
    

    Di cui sopra funziona, ma le cose sono molto più facili se il codice dinamico è spostato di una subroutine alla fine del file. Il codice può espandersi e contrarsi senza limitazione alcuna, e senza la necessità di imbottitura. FINDSTR è molto più veloce rispetto PER /F a rimuovere la parte dinamica. Linee dinamiche possono essere tranquillamente essere preceduto da un punto e virgola (incluse le etichette!). Quindi FINDSTR /V opzione viene utilizzata per escludere le righe che iniziano con un punto e virgola e il nuovo codice dinamico può essere semplicemente aggiunto.

    @echo off
    setlocal DisableDelayedExpansion
    echo The starting filesize is %~z0
    
    :loop
    echo ----------------------
    call :dynamicCode1
    call :dynamicCode2
    echo The current value=%value%
    call :changeBatch
    set /p "quit=Enter Q to quit, anything else to continue: "
    if /i "%quit%"=="Q" exit /b
    goto :loop
    
    :changeBatch
    (
      findstr /v "^;" "%~f0"
      setlocal enableDelayedExpansion
      set /a newValue=value+1, extra=!random!%%9
      echo ;:dynamicCode1
      echo ;set value=!newValue!
      echo ;exit /b
      echo ;
      echo ;:dynamicCode2
      for /l %%n in (1 1 !extra!) do echo ;echo extra line %%n
      echo ;exit /b
      endlocal
    ) >"%~f0.tmp"
    move /y "%~f0.tmp" "%~f0" > nul
    echo The new filesize is %~z0
    exit /b
    
    ;:dynamicCode1
    ;set value=33
    ;exit /b
    ;
    ;:dynamicCode2
    ;echo extra line 1
    ;exit /b
    
    • EDIT – ho modificato l’ultimo codice per dimostrare che anche le etichette possono essere preceduti, così essi possono essere facilmente inclusi in il codice dinamico.
  4. 5

    Risposta breve: sì, file batch possono modificare se stessi mentre sono in esecuzione. Come altri hanno già confermato la.

    Anni e anni fa, prima ancora che Windows 3, il posto in cui ho lavorato aveva all’interno un sistema di menu in MS-DOS. Il modo in cui ha funzionato cose era molto elegante: si effettivamente eseguito da un file batch che il programma principale (scritto in C) modificare, per l’esecuzione di script. Questo trucco significava che il menu del programma di per sé non occupare spazio in memoria, mentre le selezioni erano in esecuzione. E questo, cose come la LAN programma di Posta e il terminale 3270 programma.

    Ma in esecuzione da un auto-modifica file batch il suo significato script potrebbe anche fare cose come caricare i programmi TSR, e infatti sono in grado di fare praticamente qualsiasi cosa che si potrebbe mettere in un file batch. Che ha reso molto potente. Solo il GOTO comando non ha funzionato, fino a quando l’autore finalmente capito come fare il file batch riavviare automaticamente ad ogni comando.

  5. 4

    Quasi come sfogo detto, cmd.exe ricordate la posizione del file (non solo la posizione della linea) è attualmente, e anche per ciascuna chiamata spinge la posizione del file su un invisble stack.

    Che significa che è possibile modificare i file mentre è in esecuzione dietro e davanti l’effettiva posizione del file, avete solo bisogno di sapere cosa fare …

    Un piccolo campione di un auto modifica batch

    Cambia la linea set value=1000 continuamente

    @echo off
    setlocal DisableDelayedExpansion
    :loop
    REM **** the next line will be changed
    set value=1000
    rem ***
    echo ----------------------
    echo The current value=%value%
    <nul set /p ".=Press a key"
    pause > nul
    echo(
    (
    call :changeBatch
    rem This should be here and it should be long
    )
    rem ** It is neccessary, that this is also here!
    goto :loop
    rem ...
    :changeBatch
    set /a n=0
    set /a newValue=value+1
    set /a toggle=value %% 2
    set "theNewLine=set value=%newValue%"
    if %toggle%==0 (
       set "theNewLine=%theNewLine% & rem This adds 50 byte to the filesize.........."
    )
    del "%~f0.tmp" 2> nul
    for /F "usebackq delims=" %%a in ("%~f0") DO (
       set /a n+=1
       set "line=%%a"
       setlocal EnableDelayedExpansion
       if !n!==5 (
           (echo !theNewLine!)
       ) ELSE (
           (echo !line!)
       )
       endlocal
    ) >> "%~f0.tmp"
    (
      rem the copy should be done in a parenthesis block
      copy "%~f0.tmp" "%~f0" > nul
      if Armageddon==TheEndOfDays (
       echo This can't never be true, or is it?
      )
    )
    echo The first line after the replace action....
    echo The second line comes always after the first line?
    echo The current filesize is now %~z0
    goto :eof 
    
    • +1 Che è un divertente esempio di ciò che è possibile 🙂
  6. 3

    L’interprete dei comandi sembra ricordare l’offset dei byte all’interno di ogni file di comandi di lettura, ma il file non è bloccato, quindi è possibile apportare modifiche, dire con un editor di testo, mentre è in esecuzione.

    Se viene apportata una modifica al file dopo questa ricordato posizione, l’interprete dovrebbe felicemente continuare a eseguire l’ora script modificato. Tuttavia, se il cambiamento è fatto prima di quel punto, e che la modifica cambia la lunghezza del testo in quel punto (per esempio hai inserito o rimosso un po ‘ di testo), che ricordava posizione è ora non è più riferimento per l’inizio del prossimo comando. Quando l’interprete cerca di leggere il prossimo ‘linea’ sarà invece prendere una linea diversa, o forse parte di una riga a seconda di quanto il testo è stato inserito o rimosso. Se siete fortunati, probabilmente non sarà in grado di elaborare qualsiasi parola capita di atterrare, dare un messaggio di errore e continuare a eseguire dalla riga successiva – ma ancora probabilmente non è quello che vuoi.

    Tuttavia, con la comprensione di ciò che sta succedendo, è possibile strutturare il vostro script per ridurre il rischio. Ho scripts per implementare un semplice sistema di menu, mediante la visualizzazione di un menu, accettare input da parte dell’utente che utilizza il choice comando, e quindi l’elaborazione di selezione. Il trucco è quello di assicurarsi che il punto in cui lo script attende l’input è vicino alla parte superiore del file, in modo che tutte le modifiche che si potrebbe voler fare avverrà dopo che punto ed in modo da non avere brutte conseguenze.

    Esempio:

    :top
    call :displayMenu
    :prompt
    REM The script will spend most of its time waiting here.
    choice /C:1234 /N "Enter selection: "
    if ERRORLEVEL == 4 goto DoOption4
    if ERRORLEVEL == 3 goto DoOption3
    if ERRORLEVEL == 2 goto DoOption2
    goto DoOption1
    :displayMenu
    (many lines to display menu)
    goto prompt
    :DoOption1
    (many lines to do Option 1)
    goto top
    :DoOption2
    (many lines to do Option 2)
    goto top
    (etc)
    

Lascia un commento