windows “Droplet”批处理脚本 - 包含与号的文件名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8547676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Droplet" batch script - filenames containing ampersands
提问by stephenwade
I'm trying to create a batch file that can have other files dropped onto it. Specifically, I'm using ffmpegto edit audio files produced by a handheld voice recorder. The problem is when using filenames with ampersands (&). Even when quoting the input, anything after the & is dropped off, but only when files are dropped onto it; if the filename input is typed on the command line, the script works fine. Before the cmd
window closes, I briefly see the rest of the filename with an error saying it is not recognized as a valid command.
我正在尝试创建一个批处理文件,可以将其他文件放入其中。具体来说,我正在使用ffmpeg来编辑由手持录音机生成的音频文件。问题是在使用带有与号 (&) 的文件名时。即使在引用输入时,& 之后的任何内容都被删除,但仅当文件被删除时;如果在命令行上输入文件名输入,则脚本可以正常工作。在cmd
窗口关闭之前,我简要地看到了文件名的其余部分,并显示一条错误消息,指出它未被识别为有效命令。
Here's my script:
这是我的脚本:
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
Here's what appears on the command line, after dropping "ch17&18.mp3"
:
这是删除后命令行上显示的内容"ch17&18.mp3"
:
C:\Users\computergeeksjw\Desktop>C:\Users\computergeeksjw\ffmpeg.exe -i "ch17" -ac 1 -vol 1024 "ch17 fixed" [...] ch17: No such file or directory
In case it matters: I'm using the Windows 8 Developer Preview. Is this causing my problem? Does the same error occur on Windows 7 or earlier?
以防万一:我使用的是 Windows 8 开发人员预览版。这会导致我的问题吗?在 Windows 7 或更早版本上是否会出现同样的错误?
回答by dbenham
There is a long-standing bug in Windows drag and drop functionality regarding file paths that contain &
or ^
but don't contain a <space>
.
Windows 拖放功能中存在一个长期存在的错误,涉及包含&
或^
不包含<space>
.
If a file path contains at least one <space>
, then Windows automatically encloses the path in quotes so that it gets parsed properly. Windows should do the same thing if the file path contains &
or ^
, but it does not.
如果文件路径至少包含一个<space>
,则 Windows 会自动将该路径括在引号中,以便对其进行正确解析。如果文件路径包含&
或^
,Windows 应该做同样的事情,但它没有。
If you create the following simple batch file and drag files onto it, you can see the problem.
如果您创建以下简单的批处理文件并将文件拖到其中,您就可以看到问题所在。
@echo off
setlocal enableDelayedExpansion
echo cmd=!cmdcmdline!
echo %%1="%~1"
pause
exit
The !cmdcmdline! variable contains the actual command that launched the batch file. The batch file prints out the command line and the first parameter.
!cmd命令行!变量包含启动批处理文件的实际命令。批处理文件打印出命令行和第一个参数。
If you drag and drop a file named "a.txt" you get
如果你拖放一个名为“a.txt”的文件,你会得到
cmd=cmd /c ""C:\test\drag.bat" C:\test\a.txt"
%1=C:\test\a.txt
Press any key to continue . . .
If you disregard the quotes around the entire command you see that there are no quotes around the file argument. There are no special characters, so there is no problem.
如果您忽略整个命令周围的引号,您会看到文件参数周围没有引号。没有特殊字符,所以没有问题。
Now drag and drop "a b.txt" and you get
现在拖放“a 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 . . .
You can see how Windows detects the space in the name and encloses the file in quotes. Again there is no problem.
您可以看到 Windows 如何检测名称中的空格并将文件括在引号中。再次没有问题。
Now drag and drop "a&b.txt" and you get
现在拖放“a&b.txt”,你会得到
cmd=cmd /c ""C:\test\drag.bat" C:\test\a&b.txt"
%1=C:\test\a
Press any key to continue . . .
Windows doesn't find a space in the name, so it does not enclose it in quotes. Big problem! Windows passes "C:\test\a" to the batch file and treats "b.txt" as a second file to be executed after the batch file completes. The hard EXIT command in the batch file prevents any split filenames from executing after the batch. Of course b.txt could never execute. But if the file were named "a&b.bat" and "b.bat" existed, then that could be trouble if the hard EXIT were not in the batch file.
Windows 在名称中找不到空格,因此不会将其括在引号中。大问题!Windows 将“C:\test\a”传递给批处理文件,并将“b.txt”视为批处理文件完成后要执行的第二个文件。批处理文件中的硬 EXIT 命令可防止在批处理之后执行任何拆分文件名。当然 b.txt 永远无法执行。但是,如果文件名为“a&b.bat”并且存在“b.bat”,那么如果批处理文件中没有硬 EXIT,那可能会很麻烦。
It is possible to drag multiple files onto a batch file, and each one should be passed as a parameter.
可以将多个文件拖到一个批处理文件中,每个文件都应该作为参数传递。
The !cmdcmdline! is the only way to reliably access drag and drop arguments. But that will not work if files are passed as normal arguments in a normal call to the batch file.
!cmd命令行!是可靠访问拖放参数的唯一方法。但是,如果文件在对批处理文件的正常调用中作为正常参数传递,那将不起作用。
Below is a batch file that can detect if it was called using drag and drop versus a normal call. (It is not bullet proof, but I think it should work in most situations) It will process each file argument, one at a time, regardless of the type of call. (The process simply echos the file name, but you can substitute whatever processing you want.) If the batch was called using drag and drop then it will do a hard exit to protect against split file names.
下面是一个批处理文件,可以检测它是使用拖放调用还是正常调用调用。(它不是防弹的,但我认为它应该在大多数情况下工作)它会处理每个文件参数,一次一个,无论调用类型如何。(该过程只是回显文件名,但您可以替换任何您想要的处理。)如果使用拖放调用批处理,那么它将执行硬退出以防止拆分文件名。
@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
)
It looks like your existing batch is only designed to handle one file. I can't tell if you need to make modifications to the calls to support multiple files. I modified the above batch to only process the first argument, and substituted your process into the argument processing loop. This is untested, but I think it should work for you.
看起来您现有的批处理仅设计用于处理一个文件。我不知道您是否需要修改调用以支持多个文件。我将上面的批处理修改为仅处理第一个参数,并将您的过程替换为参数处理循环。这是未经测试的,但我认为它应该适合你。
@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
)
回答by Weaver
I admire dbenham's batch programming skills in silent awe. I tried his solution and stumbled upon two problems that I present here as I don't have enough reputation to comment:
我默默地敬佩 dbenham 的批处理编程技巧。我尝试了他的解决方案并偶然发现了我在这里提出的两个问题,因为我没有足够的声誉来发表评论:
There seems to be an extra space in front of the last quotation mark on line 15 of his batch template. I suppose it should read:
set "args=!cmd2:~0,-1!"
Someone with not-so-stellar batch programming knowledge could have serious problems finding this, like me. I tried but was unable to edit dbenham's post because of the stupid "Edits must be at least 6 characters" limitation.
The solution is generally not suitable for files/folders containing
,
(comma) or;
(semicolon) in their full path. It can be modified to work in case there is only onefile/folder dropped onto a batch file by enclosing args in quotes on line 20:for %%F in ("!args!") do (
When more than onefile/folder is dropped onto a batch file, I am afraid no general workaround of the Windows bug is possible that could cope with comma/semicolon in file path. The SendTo mechanism of Windows obviously has the very same deficiency (bug), so can't be used to work around the drag-and-drop bug. It is thus up to Microsoft to finally fix this bug.
他的批处理模板第15行最后一个引号前面好像多了一个空格。我想它应该是:
set "args=!cmd2:~0,-1!"
像我一样,具有不太出色的批处理编程知识的人在发现这个问题时可能会遇到严重的问题。我尝试过但由于愚蠢的“编辑必须至少为 6 个字符”限制而无法编辑 dbenham 的帖子。
该解决方案通常不适用于完整路径中包含
,
(逗号) 或;
(分号) 的文件/文件夹。通过将参数括在第 20 行的引号中,可以修改它以在只有一个文件/文件夹放到批处理文件中的情况下工作:for %%F in ("!args!") do (
当一个以上的文件/文件夹被放到一个批处理文件中时,恐怕没有通用的 Windows 错误解决方法可以处理文件路径中的逗号/分号。Windows 的 SendTo 机制显然也有同样的缺陷(bug),所以不能用来解决拖放问题。因此,最终由 Microsoft 修复此错误。