Перетащите пакетный файл для нескольких файлов? - PullRequest
28 голосов
/ 07 августа 2009

Я написал командный файл для использования PngCrush для оптимизации изображения .png при перетаскивании его в командный файл.

В следующем разделе я написал о том, что я считаю хорошим обновлением командного файла.

Мой вопрос: Возможно ли создать командный файл, как я делал в посте, но способен оптимизировать несколько изображений одновременно? Перетащите несколько файлов .png на него? (и вывод должен быть что-то вроде new.png, new (1) .png, new (2) .png и т. д. *

Ответы [ 5 ]

43 голосов
/ 07 августа 2009

Да, конечно, это возможно. При перетаскивании нескольких файлов в пакетный файл вы получаете список удаленных файлов в виде списка через пробел. Вы можете проверить это с помощью простой следующей партии:

@echo %*
@pause

Теперь у вас есть два варианта:

  1. PngCrush уже может обрабатывать несколько имен файлов, указанных ему в командной строке. В этом случае все, что вам нужно будет сделать, это передать %* в PngCrush вместо простого %1 (как вы, вероятно, делаете сейчас):

    @pngcrush %*
    

    %* содержит все аргументы в пакетном файле, так что это удобный способ передать все аргументы в другую программу. Осторожнее с файлами, названными как опции PngCrush. Гики UNIX будут знать эту проблему: -)

    Однако после прочтения вашего поста, описывающего вашу технику, это не будет работать должным образом, поскольку вы записываете сжатый файл в new.png. Плохая идея, если вы обрабатываете несколько файлов одновременно, поскольку может быть только один new.png :-). Но я только что попробовал, что PngCrush хорошо обрабатывает несколько файлов, поэтому, если вы не возражаете против обновления файлов на месте, поместите

    @pngcrush -reduce -brute %*
    

    в вашу партию выполнит эту работу (после вашей оригинальной статьи).

  2. PngCrush не будет обрабатывать несколько файлов или , которые вы хотите записать каждое изображение в новый файл после сжатия. В этом случае вы придерживаетесь своего "одного файла в время "рутина, но вы перебираете входные аргументы. В этом случае проще всего создать небольшой цикл и shift аргументы при каждой обработке:

    @echo off
    if [%1]==[] goto :eof
    :loop
    pngcrush -reduce -brute %1 "%~dpn1_new%~x1"
    shift
    if not [%1]==[] goto loop
    

    То, что мы делаем здесь, просто: сначала мы пропускаем весь пакет, если он запускается без аргументов, затем определяем метку, к которой нужно перейти: loop. Внутри мы просто запускаем PngCrush для первого аргумента, давая сжатому файлу новое имя. Возможно, вы захотите прочитать синтаксис разбора пути, который я использовал здесь в help call. В основном то, что я делаю здесь, это имя файла в точности как раньше; Я просто прикрепляю «_new» к концу имени файла (перед расширением). %~dpn1 расширяется до диска, пути и имени файла (без расширения), а %~x1 расширяется до расширения, включая точку.

    ETA: Eep, я только что прочитал ваш желаемый вывод с помощью new.png, new (1) .png и т. Д. В этом случае нам не нужны какие-либо причудливые рассечения путей, но у нас есть другие проблемы заботиться о.

    Самый простой способ, вероятно, состоит в том, чтобы просто запустить счетчик с 0 до того, как мы обработаем первый файл, и увеличивать его каждый раз, когда обрабатываем другой:

    @echo off
    if [%1]==[] goto :eof
    set n=0
    :loop
    if %n%==0 (
        pngcrush -reduce -brute %1 new.png
    ) else (
        pngcrush -reduce -brute %1 new^(%n%^).png
    )
    shift
    set /a n+=1
    if not [%1]==[] goto loop
    

    %n% - наш счетчик, и мы обрабатываем случай, когда n равен 0, записывая результат в new.png вместо new(0).png.

    Однако у этого подхода есть проблемы. Если уже есть файлы с именами new.png или new(x).png, то вы, вероятно, ударите их. Не хорошо. Поэтому мы должны сделать что-то другое и проверить, действительно ли мы можем использовать имена файлов:

    rem check for new.png
    if exist new.png (set n=1) else (set n=0 & goto loop)
    rem check for numbered new(x).png
    :checkloop
    if not exist new^(%n%^).png goto loop
    set /a n+=1
    goto checkloop
    

    Остальная часть программы остается неизменной, включая обычный цикл. Но теперь мы начинаем с первого неиспользуемого имени файла и избегаем перезаписи уже существующих файлов.

Не стесняйтесь адаптироваться по мере необходимости.

10 голосов
/ 20 марта 2011

Безопасно выполнять перетаскивание с помощью пакета.

Работа с %1, shift или %* может завершиться неудачей, поскольку проводник не очень умен, при цитировании имен файлов приводятся только имена файлов с пробелами.
Но такие файлы, как Cool&stuff.png, не цитируются проводником, поэтому вы получаете команду типа

pngCr.bat Cool&stuff.png

Таким образом, в %1 есть только Cool, даже в %* есть только Cool, но после завершения пакета cmd.exe пытается выполнить stuff.png (и завершится ошибкой).

Для этого вы можете получить доступ к параметрам с помощью !cmdcmdline! вместо %1 .. %n, и чтобы обойти потенциальную ошибку в конце выполнения, может помочь простой exit.

@echo off
setlocal ENABLEDELAYEDEXPANSION
rem Take the cmd-line, remove all until the first parameter
set "params=!cmdcmdline:~0,-1!"
set "params=!params:*" =!"
set count=0

rem Split the parameters on spaces but respect the quotes
for %%G IN (!params!) do (
  set /a count+=1
  set "item_!count!=%%~G"
  rem echo !count! %%~G
)

rem list the parameters
for /L %%n in (1,1,!count!) DO (
  echo %%n #!item_%%n!#
)
pause

REM ** The exit is important, so the cmd.ex doesn't try to execute commands after ampersands
exit

Btw. есть предел строки для операций перетаскивания ~ 2048 символов, несмотря на "стандартный" предел строки партии ~ 8192 символа.
Поскольку для каждого файла указан полный путь, этот предел может быть достигнут с помощью нескольких файлов.

2 голосов
/ 25 ноября 2014
FOR %%A IN (%*) DO (
    REM Now your batch file handles %%A instead of %1
    REM No need to use SHIFT anymore.
    ECHO %%A
)

А чтобы различать удаленные файлы и папки, вы можете использовать это:

FOR %%I IN (%*) DO (
    ECHO.%%~aI | FIND "d" >NUL
    IF ERRORLEVEL 1 (
        REM Processing Dropped Files
        CALL :_jobF "%%~fI"
    ) ELSE (
        REM Processing Dropped Folders
        CALL :_jobD "%%~fI"
    )
)
1 голос
/ 17 августа 2018

Это очень поздний ответ. На самом деле я не знал об этом старом вопросе и подготовил ответ на этот аналогичный вопрос, в котором обсуждалась обработка имен файлов специальными символами, поскольку проводник только цитирует файл имена, которые содержат пробел (ы). Затем в комментариях к этому вопросу я увидел ссылку на эту ветку, после этого, а не на свою уверенную в себе информацию, я понял, что jeb уже раскрыл и очень хорошо объяснил этот вопрос, что от него ожидается.

Таким образом, без каких-либо дополнительных пояснений я внесу свое решение с основным упором на то, чтобы охватить более особые случаи в именах файлов с этими ,;!^ символами, а также предоставить механизм для предположения , если пакетный файл напрямую запускается проводником или нет, поэтому во всех случаях можно использовать старую логику для обработки аргументов пакетного файла.

@echo off
setlocal DisableDelayedExpansion

if "%~1" EQU "/DontCheckDrapDrop" (
    shift
) else (
    call :IsDragDrop && (
        call "%~f0" /DontCheckDrapDrop %%@*%%
        exit
    )    
)

:: Process batch file arguments as you normally do 
setlocal EnableDelayedExpansion
echo cmdcmdline=!cmdcmdline!
endlocal

echo,
echo %%*=%*
echo,
if defined @* echo @*=%@*%
echo,
echo %%1="%~1"
echo %%2="%~2"
echo %%3="%~3"
echo %%4="%~4"
echo %%5="%~5"
echo %%6="%~6"
echo %%7="%~7"
echo %%8="%~8"
echo %%9="%~9"
pause
exit /b

:: IsDragDrop routine
:: Checks if the batch file is directly lanched through Windows Explorer
:: then Processes batch file arguments which are passed by Drag'n'Drop,
:: rebuilds a safe variant of the arguments list suitable to be passed and processed
:: in a batch script and returns the processed args in the environment variable
:: that is specified by the caller or uses @* as default variable if non is specified.
:: ErrorLevel: 0 - If launched through explorer. 1 - Otherwise (Will not parse arguments)
:IsDragDrop [retVar=@*]
setlocal
set "Esc="
set "ParentDelayIsOff=!"

setlocal DisableDelayedExpansion
if "%~1"=="" (set "ret=@*") else set "ret=%~1"
set "Args="
set "qsub=?"

:: Used for emphasis purposes
set "SPACE= "

setlocal EnableDelayedExpansion
set "cmdline=!cmdcmdline!"
set ^"ExplorerCheck=!cmdline:%SystemRoot%\system32\cmd.exe /c ^""%~f0"=!^"
if "!cmdline!"=="!ExplorerCheck!" (
    set ^"ExplorerCheck=!cmdline:"%SystemRoot%\system32\cmd.exe" /c ^""%~f0"=!^"
    if "!cmdline!"=="!ExplorerCheck!" exit /b 1
)
set "ExplorerCheck="
set ^"cmdline=!cmdline:*"%~f0"=!^"
set "cmdline=!cmdline:~0,-1!"
if defined cmdline (
    if not defined ParentDelayIsOff (
        if "!cmdline!" NEQ "!cmdline:*!=!" set "Esc=1"
    )
    set ^"cmdline=!cmdline:"=%qsub%!"
)
(
    endlocal & set "Esc=%Esc%"
    for /F "tokens=*" %%A in ("%SPACE% %cmdline%") do (
        set "cmdline=%%A"
    )
)
if not defined cmdline endlocal & endlocal & set "%ret%=" & exit /b 0

:IsDragDrop.ParseArgs
if "%cmdline:~0,1%"=="%qsub%" (set "dlm=%qsub%") else set "dlm= "
:: Using '%%?' as FOR /F variable to not mess with the file names that contain '%'
for /F "delims=%dlm%" %%? in ("%cmdline%") do (
    set ^"Args=%Args% "%%?"^"
    setlocal EnableDelayedExpansion
    set "cmdline=!cmdline:*%dlm: =%%%?%dlm: =%=!"
)
(
    endlocal
    for /F "tokens=*" %%A in ("%SPACE% %cmdline%") do (
        set "cmdline=%%A"
    )
)
if defined cmdline goto :IsDragDrop.ParseArgs

if defined Esc (
    set ^"Args=%Args:^=^^%^"
)
if defined Esc (
    set ^"Args=%Args:!=^!%^"
)
(
    endlocal & endlocal
    set ^"%ret%=%Args%^"
    exit /b 0
)

ВЫХОД с перетаскиваемыми образцами файлов в пакетный файл:

cmdcmdline=C:\Windows\system32\cmd.exe /c ""Q:\DragDrop\DragDrop.cmd" Q:\DragDrop\ab.txt "Q:\DragDrop\c d.txt" Q:\DragDrop\!ab!c.txt "Q:\DragDrop\a b.txt" Q:\DragDrop\a!b.txt Q:\DragDrop\a&b.txt Q:\DragDrop\a(b&^)).txt Q:\DragDrop\a,b;c!d&e^f!!.txt Q:\DragDrop\a;b.txt"

%*=/DontCheckDrapDrop  "Q:\DragDrop\ab.txt" "Q:\DragDrop\c d.txt" "Q:\DragDrop\!ab!c.txt" "Q:\DragDrop\a b.txt" "Q:\DragDrop\a!b.txt" "Q:\DragDrop\a&b.txt" "Q:\DragDrop\a(b&^)).txt" "Q:\DragDrop\a,b;c!d&e^f!!.txt" "Q:\DragDrop\a;b.txt"

@*= "Q:\DragDrop\ab.txt" "Q:\DragDrop\c d.txt" "Q:\DragDrop\!ab!c.txt" "Q:\DragDrop\a b.txt" "Q:\DragDrop\a!b.txt" "Q:\DragDrop\a&b.txt" "Q:\DragDrop\a(b&^)).txt" "Q:\DragDrop\a,b;c!d&e^f!!.txt" "Q:\DragDrop\a;b.txt"

%1="Q:\DragDrop\ab.txt"
%2="Q:\DragDrop\c d.txt"
%3="Q:\DragDrop\!ab!c.txt"
%4="Q:\DragDrop\a b.txt"
%5="Q:\DragDrop\a!b.txt"
%6="Q:\DragDrop\a&b.txt"
%7="Q:\DragDrop\a(b&^)).txt"
%8="Q:\DragDrop\a,b;c!d&e^f!!.txt"
%9="Q:\DragDrop\a;b.txt"

В процедуре :IsDragDrop я специально пытался минимизировать предположения о формате командной строки и интервале между аргументами. Обнаружение (предположение) для запуска проводника основано на этой сигнатуре командной строки %SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments"

Так что очень легко обмануть код, думая, что он запущен двойным щелчком из проводника или перетаскиванием, и это не проблема, и командный файл будет работать нормально.

Но с этой конкретной сигнатурой невозможно преднамеренно запустить пакетный файл следующим образом: %SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments & SomeOtherCommand" и ожидать выполнения SomeOtherCommand, вместо этого он будет объединен с аргументами пакетного файла.

0 голосов
/ 29 сентября 2016

Вам не нужен пакетный скрипт для оптимизации нескольких PNG, все, что вам нужно, это подстановочный знак:

pngcrush -d "crushed" *.png

Это pngcrush все PNG в текущем dir и переместит их в sub-dir под названием "Crushed". Я бы добавил флаг -brute, чтобы, вероятно, сбрить еще несколько байтов.

pngcrush -d "crushed" -brute *.png

Я публикую это, потому что это не очень хорошо документировано или широко известно, и потому что это может быть проще для вас в долгосрочной перспективе, чем написание и ведение пакетного файла перетаскивания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...