拖放多个文件的批处理文件?
我编写了一个批处理文件,以便在将 .png 图像拖放到批处理文件中时使用 PngCrush 来优化该图像。
在下一节中,我写了我认为对批处理文件的一个很好的升级。
我的问题是:是否可以像我在帖子中那样创建一个批处理文件,但能够同时优化多个图像? 拖放多个 .png 文件到其上? (并且输出类似于 new.png、new(1).png、new(2).png 等...
I wrote a batch file to use PngCrush to optimize a .png image when I drag and drop it onto the batch file.
In the what's next section, I wrote about what I thought would be a good upgrade to the batch file.
My question is: is it possible to create a batch file like I did in the post, but capable of optimizing multiple images at once? Drag and drop multiple .png files on it? (and have the output be something like new.png, new(1).png, new(2).png, etc...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的,这当然是可能的。 在批处理文件上拖动多个文件时,您将获得以空格分隔的已放置文件的列表。 您可以通过以下简单的批处理来验证这一点:
现在您有两个选择:
PngCrush 已经可以处理在命令行上为其指定的多个文件名。在这种情况下,您所要做的就是要做的就是将
%*
传递给 PngCrush 而不是仅仅%1
(就像您现在可能做的那样):<前><代码>@pngcrush %*
%*
包含批处理文件的所有参数,因此这是将所有 参数传递给另一个程序的便捷方法。 不过,要小心名为 PngCrush 选项之类的文件。 UNIX 极客会知道这个问题:-)但是,在阅读描述您的技术的帖子后,当您将压缩文件写入
new.png
时,这将无法正常工作。 如果您一次处理多个文件,这是一个坏主意,因为只能有一个new.png
:-)。 但我刚刚尝试过 PngCrush 可以很好地处理多个文件,因此如果您不介意就地更新文件,则可以将<前><代码>@pngcrush -reduce -brute %*
进入你的批处理将完成这项工作(按照你的原始文章)。
PngCrush 不会处理多个文件或者您希望在压缩后将每个图像写入一个新文件。在这种情况下,您坚持使用“一次一个文件” " 例程,但您循环输入参数。 在这种情况下,最简单的方法是构建一个小循环,并在每次处理一个循环时
移动
参数:<前><代码>@echo 关闭
if [%1]==[] 转到 :eof
:环形
pngcrush -reduce -brute %1“%~dpn1_new%~x1”
转移
if not [%1]==[] 转到循环
我们在这里所做的很简单:首先,如果整个批处理在没有参数的情况下运行,我们会跳过整个批处理,然后我们定义一个要跳转到的标签:
loop
。 在内部,我们只需对第一个参数运行 PngCrush,为压缩文件指定一个新名称。 您可能需要阅读我在help call
中使用的路径剖析语法。 基本上我在这里所做的就是像以前一样命名文件; 我只是将“_new”粘贴到文件名的末尾(扩展名之前)。%~dpn1
扩展为驱动器、路径和文件名(不带扩展名),而%~x1
扩展为扩展名,包括点。预计到达时间: Eep,我刚刚用 new.png、new(1).png 等读取了您想要的输出。在这种情况下,我们不需要任何花哨的路径剖析,但我们有其他需要关心的问题。
最简单的方法可能是在处理第一个文件之前从 0 开始计数器,并在每次处理另一个文件时递增它:
<前><代码>@echo 关闭
if [%1]==[] 转到 :eof
设 n=0
:环形
如果%n%==0(
pngcrush-reduce-brute %1 new.png
) 别的 (
pngcrush -reduce -brute %1 新^(%n%^).png
)
转移
设置/a n+=1
if not [%1]==[] 转到循环
%n%
是我们的计数器,我们通过将结果写入new.png
来处理n
为 0 的情况,而不是new(0).png
。但是这种方法有问题。 如果已经存在名为
new.png
或new(x).png
的文件,那么您可能会破坏它们。 不太好。 所以我们必须做一些不同的事情并检查我们是否真的可以使用文件名:程序的其余部分保持不变,包括正常循环。 但现在我们从第一个未使用的文件名开始,避免覆盖已经存在的文件。
请随意根据需要进行调整。
Yes, of course this is possible. When dragging multiple files on a batch file you get the list of dropped files as a space-separated list. You can verify this with the simple following batch:
Now you have two options:
PngCrush can already handle multiple file names given to it on the command line. In this case all you'd have to do would be to pass
%*
to PngCrush instead of just%1
(as you probably do now):%*
contains all arguments to the batch file, so this is a convenient way to pass all arguments to another program. Careful with files named like PngCrush options, though. UNIX geeks will know that problem :-)After reading your post describing your technique, however, this won't work properly as you are writing the compressed file to
new.png
. A bad idea if you're handling multiple files at once as there can be only onenew.png
:-). But I just tried out that PngCrush handles multiple files just well, so if you don't mind an in-place update of the files then puttinginto your batch will do the job (following your original article).
PngCrush will not handle multiple files or you want to write each image to a new file after compression. In this case you stick with your "one file at a time" routine but you loop over the input arguments. In this case, it's easiest to just build a little loop and
shift
the arguments each time you process one:What we're doing here is simple: First we skip the entire batch if it is run without arguments, then we define a label to jump to:
loop
. Inside we simply run PngCrush on the first argument, giving the compressed file a new name. You may want to read up on the path dissection syntax I used here inhelp call
. Basically what I'm doing here is name the file exactly as before; I just stick "_new" to the end of the file name (before the extension).%~dpn1
expands to drive, path and file name (without extension), while%~x1
expands to the extension, including the dot.ETA: Eep, I just read your desired output with new.png, new(1).png, etc. In this case we don't need any fancy path dissections but we have other problems to care about.
The easiest way would probably be to just start a counter at 0 before we process the first file and increment it each time we process another one:
%n%
is our counter here and we handle the case wheren
is 0 by writing the result tonew.png
, instead ofnew(0).png
.This approach has problems, though. If there are already files named
new.png
ornew(x).png
then you will probably clobber them. Not nice. So we have to do something different and check whether we can actually use the file names:The rest of the program stays the same, including the normal loop. But now we start at the first unused file name and avoid overwriting files that are already there.
Feel free to adapt as needed.
进行拖放操作 以安全的方式投放,并不是批量那么简单。
处理
%1
、shift
或%*
可能会失败,因为资源管理器不是很智能,在引用文件名时,仅引用带有空格的文件名已被引用。但是像
Cool&stuff.png
这样的文件不会被资源管理器引用,所以你会得到一个像So in
%1
is onlyCool
即使在%*
只是Cool
,但是批处理结束后,cmd.exe 会尝试执行stuff.png
(并且会失败)。要处理此问题,您可以使用
!cmdcmdline!
而不是%1
..%n
访问参数,为了绕过执行结束时的潜在错误,简单的
exit
可能会有所帮助。顺便提一句。 尽管“标准”批处理行限制为 ~8192 个字符,但拖放操作的行限制为 ~2048 个字符。
对于每个文件都传递完整路径,很少有文件就可以达到此限制。
To do Drag & Drop in a secure way, isn't so simple with batch.
Dealing with
%1
,shift
or%*
could fail, because the explorer is not very smart, while quoting the filenames, only filenames with spaces are quoted.But files like
Cool&stuff.png
are not quoted by the explorer so you get a cmdline likeSo in
%1
is onlyCool
even in%*
is onlyCool
, but after the batch ends, cmd.exe tries to execute astuff.png
(and will fail).To handle this you could access the parameters with
!cmdcmdline!
instead of%1
..%n
,and to bypass a potential error at the end of execution, a simple
exit
could help.Btw. there is a line limit for drag&drop operations of ~2048 characters, in spite of the "standard" batch line limit of ~8192 characters.
As for each file the complete path is passed, this limit can be reached with few files.
为了区分删除的文件和文件夹,您可以使用以下命令:
And to differentiate between dropped files and folders, you can use this:
这是一个很晚的答案,实际上我不知道这个老问题并准备了答案 这类似的一个,其中讨论了如何处理带有特殊字符的文件名,因为资源管理器仅引用包含空格的文件名。 然后在对该问题的评论中,我看到了对该线程的引用,之后我意识到 jeb这件事已经很好地涵盖和解释了,这是对他的期望。
因此,无需任何进一步的解释,我将贡献我的解决方案,主要关注使用此
,;!^
字符的文件名中的更多特殊情况,并提供一种猜测机制 如果批处理文件是否由资源管理器直接启动,那么在所有情况下都可以使用处理批处理文件参数的旧时尚逻辑。将示例文件拖放到批处理文件上的输出:
在
:IsDragDrop
例程中,我特别尝试最小化有关命令行格式和参数之间间距的假设。 对explorer启动的检测(猜测)是基于这个命令行签名%SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments"
所以很有可能欺骗代码去思考它是通过从资源管理器双击或拖放启动的,这不是问题,批处理文件将正常运行。
但使用此特定签名,不可能以这种方式有意启动批处理文件:
%SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments & SomeOtherCommand"
并期望>SomeOtherCommand
被执行,而是被合并到批处理文件参数中。This is a very late answer, Actually I was not aware of this old question and prepared an answer for this similar one where there was a discussion about handling file names with special characters because explorer only quotes file names that contain space(s). Then in the comments on that question I saw a reference to this thread, after that and not to my sureprise I realized that jeb have already covered and explained this matter very well, which is expected of him.
So without any further explanations I will contribute my solution with the main focus to cover more special cases in file names with this
,;!^
characters and also to provide a mechanism to guess if the batch file is directly launched by explorer or not, so the old fashion logic for handling batch file arguments could be used in all cases.OUTPUT with sample files dragged and dropped onto the batch file:
In
:IsDragDrop
routine I specially tried to minimize the assumptions about command line format and spacing between the arguments. The detection (guess) for explorer launch is based on this command line signature%SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments"
So it is very possible to fool the code into thinking it has launched by double click from explorer or by drag'n'drop and that's not an issue and the batch file will function normally.
But with this particular signature it is not possible to intentionally launch batch file this way:
%SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments & SomeOtherCommand"
and expect that theSomeOtherCommand
to be executed, instead it will be merged into the batch file arguments.您不需要批处理脚本来优化多个 PNG,您需要的只是通配符:
这将 pngcrush 当前目录中的所有 PNG 并将它们移动到名为“crushed”的子目录。 我会添加 -brute 标志来可能减少更多字节。
我发布此内容是因为它似乎没有很好的文档记录或广为人知,而且因为从长远来看,它可能比编写和维护拖放批处理文件更容易。
You don't need a batch script to optimize multiple PNGs, all you need is the wildcard:
That will pngcrush all PNGs in the current dir and move them to a sub-dir named "crushed". I would add the -brute flag to likely shave off a few more bytes.
I'm posting this because it doesn't seem to be well documented or widely known, and because it may be easier for you in the long run than writing and maintaining a drag and drop batch file.