2011-12-17 4 views
6

다른 파일을 떨어 뜨릴 수있는 배치 파일을 만들려고합니다. 특히 핸드 헬드 보이스 레코더에서 제작 한 오디오 파일을 편집하려면 ffmpeg을 사용하고 있습니다. 문제는 앰퍼샌드 (&)와 함께 파일 이름을 사용할 때입니다. 입력을 인용 할 때에도 & 이후의 모든 것은 삭제되지만 파일이 삭제 될 때만 삭제됩니다. 명령 줄에서 파일 이름 입력을 입력하면 스크립트가 제대로 작동합니다. cmd 창이 닫히기 전에 나머지 파일 이름을 잠시보고 그것이 유효한 명령으로 인식되지 않는다는 오류가 표시됩니다. "ch17&18.mp3"을 삭제 한 후,"Droplet"배치 스크립트 - 앰퍼샌드가 포함 된 파일 이름

 
rem Change to drive and directory of input file 
%~d1 
cd %~p1 

rem ffmpeg: mix to one channel, double the volume 
%HOMEDRIVE%%HOMEPATH%\ffmpeg.exe -i "%~nx1" -ac 1 -vol 1024 "%~n1 fixed%~x1" 

pause 

여기 명령 줄에 나타나는 내용은 다음과 같습니다 :

여기 내 스크립트의 IT 중요한

 
C:\Users\computergeeksjw\Desktop>C:\Users\computergeeksjw\ffmpeg.exe -i "ch17" -ac 1 -vol 1024 "ch17 fixed" 
[...] 
ch17: No such file or directory 

경우 : I는 윈도우 8 개발자 미리보기를 사용하고 있습니다. 이게 내 문제를 일으키는거야? Windows 7 이전 버전에서도 같은 오류가 발생합니까?

답변

13

& 또는 ^을 포함하지만 <space>을 포함하지 않는 파일 경로에 대해서는 Windows의 끌어서 놓기 기능에 오래 문제가 있습니다.

파일 경로에 적어도 하나의 <space>이 포함되어 있으면 Windows는 자동으로 경로를 따옴표로 묶어 올바르게 구문 분석합니다. 파일 경로에 & 또는 ^이 포함되어 있으면 Windows에서 동일한 작업을 수행해야하지만 그렇게하지 않아야합니다.

다음 간단한 배치 파일을 만들고 파일을 끌어다 놓으면 문제가 발생합니다.

@echo off 
setlocal enableDelayedExpansion 
echo cmd=!cmdcmdline! 
echo %%1="%~1" 
pause 
exit 

! cmdcmdline! 변수에는 배치 파일을 시작한 실제 명령이 들어 있습니다. 배치 파일은 명령 줄과 첫 번째 매개 변수를 인쇄합니다. 드래그 앤라는 이름의 파일을 삭제하면 당신이 파일 인수 주위에 따옴표가없는 것을 볼 전체 명령 주위에 따옴표를 무시하는 경우

는 "a.txt이"당신은

cmd=cmd /c ""C:\test\drag.bat" C:\test\a.txt" 
%1=C:\test\a.txt 
Press any key to continue . . . 

를 얻을. 특수 문자가 없으므로 아무런 문제가 없습니다.

지금 드래그 "는 b.txt"을 삭제하고 당신은

cmd=cmd /c ""C:\test\drag.bat" "C:\test\a b.txt"" 
%1="C:\test\a b.txt" 
Press any key to continue . . . 

당신은 Windows가 이름 공간을 감지하고 따옴표에서 파일을 둘러싸는 방법을 볼 수 있습니다 얻을. 다시 문제는 없습니다.

지금 드래그 "는 & b.txt"을 삭제하고 당신은

cmd=cmd /c ""C:\test\drag.bat" C:\test\a&b.txt" 
%1=C:\test\a 
Press any key to continue . . . 

Windows가 이름에 공간을 검색 할 수 없습니다를 얻을, 그래서 따옴표로 묶어야하지 않습니다. 큰 문제! Windows는 "C : \ test \ a"를 배치 파일에 전달하고 배치 파일이 완료된 후에 실행될 두 번째 파일로 "b.txt"를 처리합니다. 배치 파일의 하드 EXIT 명령은 배치 후에 분할 파일 이름이 실행되지 않도록합니다. 물론 b.txt는 결코 실행될 수 없습니다. 그러나 파일 이름이 "& b.bat"이고 "b.bat"라는 파일이 존재하면 하드 EXIT가 배치 파일에없는 경우 문제가 될 수 있습니다.

배치 파일에 여러 파일을 드래그하여 각 파일을 매개 변수로 전달할 수 있습니다.

! cmdcmdline! 끌어서 놓기 인수에 안정적으로 액세스하는 유일한 방법입니다. 그러나 배치 파일의 정상 호출에서 파일이 일반 인수로 전달되는 경우에는 작동하지 않습니다.

다음은 끌어서 놓기와 일반 호출을 사용하여 호출했는지를 검색 할 수있는 배치 파일입니다. (그것은 총알 증명이 아니지만 대부분의 상황에서 효과가있을 것이라고 생각합니다.) 호출 유형에 관계없이 한 번에 하나씩 각 파일 인수를 처리합니다. 이 프로세스는 단순히 파일 이름을 에코합니다. 그러나 원하는 처리를 대체 할 수 있습니다. 끌어 놓기를 사용하여 일괄 처리를 호출 한 경우 분할 파일 이름을 보호하기 위해 하드 탈출을 수행합니다.

@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 
) 

기존 배치가 하나의 파일 만 처리하도록 설계된 것처럼 보입니다. 여러 파일을 지원하기 위해 호출을 수정해야하는지 여부는 알 수 없습니다. 위의 배치를 수정하여 첫 번째 인수 만 처리하고 인수 처리 루프로 프로세스를 대체했습니다. 이 테스트되지 않은,하지만 그것은 당신을 위해 작동해야한다고 생각합니다.

@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 
) 
+0

원더풀! 훌륭하게 작동합니다. 귀찮은 일이 아니라면 첫 번째 배치 스크립트이기 때문에 스크립트가 어떻게 작동하는지 한 줄씩 설명하는 것을 좋아할 것입니다 (내 첫 프로그래밍 경험은 아니지만). 감사! – stephenwade

0

침묵의 경외심에서 dbenham의 일괄 프로그래밍 기술에 감탄했습니다. 나는 그의 해결책을 시도하고 내가 의견을 충분히 명성을 가지고 있지 않는 한 내가 여기에 선물 두 가지 문제가 우연히 :

  1. 는 라인 (15)의 마지막 인용 부호 앞에 여분의 공간이 될 것 같다을 그의 배치 템플릿. 나는 그것을 읽어야한다고 가정 그리 별 배치 프로그래밍 지식을 가진

    set "args=!cmd2:~0,-1!" 
    

    누군가가 심각한 문제 나처럼,이를 찾는데 어려움이 있었다. 나는 시도했지만 dbenham의 게시물을 편집 할 수 없었습니다. "편집은 최소 6 자 이상이어야합니다"라는 제한 때문입니다.

  2. 해결책은 일반적으로 전체 경로에 , (쉼표) 또는 ; (세미콜론)을 포함하는 파일/폴더에는 적합하지 않습니다.

    for %%F in ("!args!") do (
    

    이상의 파일/폴더를 삭제하면 : 경우에 작동하도록 수정 될 수 하나 파일/폴더 라인 (20)에 따옴표로 인수를 묶어 배치 파일에 떨어에만있다 배치 파일에 쉼표/​​세미콜론 파일 경로에 대처할 수있는 Windows 버그 일반적인 해결 방법은 없습니다. Windows의 SendTo 메커니즘에는 분명히 동일한 결함 (버그)이 있으므로 끌어서 놓기 버그를 해결하는 데 사용할 수 없습니다. 따라서 결국이 버그를 수정하는 것은 Microsoft의 책임입니다.

관련 문제