C'è un errore di vecchia data nella funzionalità di trascinamento della selezione di Windows per i percorsi di file che contengono &
o ^
ma non contengono uno <space>
.
Se un percorso file contiene almeno uno <space>
, Windows racchiude automaticamente il percorso tra virgolette affinché venga analizzato correttamente. Windows dovrebbe fare la stessa cosa se il percorso del file contiene &
o ^
, ma non è così.
Se si crea il seguente file batch semplice e si trascinano i file su di esso, è possibile visualizzare il problema.
@echo off
setlocal enableDelayedExpansion
echo cmd=!cmdcmdline!
echo %%1="%~1"
pause
exit
Il! Cmdcmdline! variabile contiene il comando effettivo che ha avviato il file batch. Il file batch stampa la riga di comando e il primo parametro.
Se si trascina un file denominato "a.txt" si ottiene
cmd=cmd /c ""C:\test\drag.bat" C:\test\a.txt"
%1=C:\test\a.txt
Press any key to continue . . .
Se non rispetti le virgolette l'intero comando si vede che non ci sono virgolette intorno l'argomento file. Non ci sono caratteri speciali, quindi non ci sono problemi.
Ora drag and drop "un b.txt" e si ottiene
cmd=cmd /c ""C:\test\drag.bat" "C:\test\a b.txt""
%1="C:\test\a b.txt"
Press any key to continue . . .
si può vedere come Windows rileva lo spazio in nome e racchiude il file tra virgolette. Anche in questo caso non ci sono problemi.
Ora drag and drop "un b.txt &" e si ottiene
cmd=cmd /c ""C:\test\drag.bat" C:\test\a&b.txt"
%1=C:\test\a
Press any key to continue . . .
di Windows non trova uno spazio nel nome, in modo che non racchiude tra virgolette. Grande problema! Windows passa "C: \ test \ a" al file batch e tratta "b.txt" come un secondo file da eseguire dopo il completamento del file batch. Il comando EXIT nel file batch impedisce l'esecuzione di eventuali nomi di file divisi dopo il batch. Ovviamente b.txt non potrebbe mai essere eseguito. Ma se il file è stato denominato "a & b.bat" e "b.bat" esisteva, questo potrebbe essere un problema se EXIT non fosse nel file batch.
E 'possibile trascinare più file su un file batch, e ognuno deve essere passato come parametro.
Il CMDCMDLINE!! è l'unico modo per accedere in modo affidabile agli argomenti di trascinamento della selezione. Ma questo non funzionerà se i file vengono passati come normali argomenti in una normale chiamata al file batch.
Qui di seguito è un file batch in grado di rilevare se è stato chiamato con il drag and drop contro una chiamata normale. (Non è a prova di proiettile, ma penso che dovrebbe funzionare nella maggior parte delle situazioni) Elaborerà ogni argomento di file, uno alla volta, indipendentemente dal tipo di chiamata. (Il processo echos semplicemente il nome del file, ma è possibile sostituire qualsiasi trattamento che si desidera). Se il lotto è stato chiamato con il drag and drop, allora lo farà un'uscita difficile per la protezione contro i nomi dei file divisi.
@echo off
setlocal disableDelayedExpansion
::
:: first assume normal call, get args from %*
set args=%*
set "dragDrop="
::
:: Now check if drag&drop situation by looking for %0 in !cmdcmdline!
:: if found then set drag&drop flag and get args from !cmdcmdline!
setlocal enableDelayedExpansion
set "cmd=!cmdcmdline!"
set "cmd2=!cmd:*%~f0=!"
if "!cmd2!" neq "!cmd!" (
set dragDrop=1
set "args=!cmd2:~0,-1! "
set "args=!args:* =!"
)
::
:: Process the args
for %%F in (!args!) do (
if "!!"=="" endlocal & set "dragDrop=%dragDrop%"
rem ------------------------------------------------
rem - Your file processing starts here.
rem - Each file will be processed one at a time
rem - The file path will be in %%F
rem -
echo Process file "%%~F"
rem -
rem - Your file processing ends here
rem -------------------------------------------------
)
::
:: If drag&drop then must do a hard exit to prevent unwanted execution
:: of any split drag&drop filename argument
if defined dragDrop (
pause
exit
)
Sembra che il gruppo esistente sia progettato per gestire un solo file. Non riesco a capire se è necessario apportare modifiche alle chiamate per supportare più file. Ho modificato il batch precedente per elaborare solo il primo argomento e sostituito il processo nel ciclo di elaborazione degli argomenti. Questo non è stato verificato, ma penso che dovrebbe funzionare per te.
@echo off
setlocal disableDelayedExpansion
::
:: first assume normal call, get args from %*
set args=%*
set "dragDrop="
::
:: Now check if drag&drop situation by looking for %0 in !cmdcmdline!
:: if found then set drag&drop flag and get args from !cmdcmdline!
setlocal enableDelayedExpansion
set "cmd=!cmdcmdline!"
set "cmd2=!cmd:*%~f0=!"
if "!cmd2!" neq "!cmd!" (
set dragDrop=1
set "args=!cmd2:~0,-1! "
set "args=!args:* =!"
)
::
:: Process the first argument only
for %%F in (!args!) do (
if "!!"=="" endlocal & set "dragDrop=%dragDrop%"
rem ------------------------------------------------
rem - Your file processing starts here.
rem - Use %%F wherever you would normally use %1
rem
rem Change to drive and directory of input file
%%~dF
cd %%~pF
rem ffmpeg: mix to one channel, double the volume
%HOMEDRIVE%%HOMEPATH%\ffmpeg.exe -i "%%~nxF" -ac 1 -vol 1024 "%%~nF fixed%%~xF"
rem
rem - Your file processing ends here
rem -------------------------------------------------
goto :continue
)
:continue
if defined dragDrop (
pause
exit
)
Meraviglioso! Funziona alla grande. Se non è un fastidio, mi piacerebbe una spiegazione riga per riga di come funziona lo script, perché questo è il mio primo script batch (anche se non è la mia prima esperienza di programmazione). Grazie! – stephenwade