Есть ли способ указать последние n параметров в пакетном файле? - PullRequest
40 голосов
/ 17 апреля 2009

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

C:\> parent.cmd child1 foo bar
C:\> parent.cmd child2 baz zoop
C:\> parent.cmd child3 a b c d e f g h i j k l m n o p q r s t u v w x y z

Внутри parent.cmd мне нужно удалить% 1 из списка параметров и передать только оставшиеся параметры дочернему сценарию.

set CMD=%1
%CMD% <WHAT DO I PUT HERE>

Я исследовал использование SHIFT с% *, но это не работает. Хотя SHIFT будет перемещать позиционные параметры вниз на 1,% * по-прежнему относится к исходным параметрам.

У кого-нибудь есть идеи? Должен ли я просто сдаться и установить Linux?

Ответы [ 8 ]

70 голосов
/ 17 апреля 2009
К сожалению,

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

rem throw the first parameter away
shift
set params=%1
:loop
shift
if [%1]==[] goto afterloop
set params=%params% %1
goto loop
:afterloop

Я думаю, что это можно сделать короче, хотя ... Я не пишу такие вещи очень часто:)

Должно работать, хотя.

15 голосов
/ 03 сентября 2013

Это однострочный подход с использованием команды "for" ...

for /f "usebackq tokens=1*" %%i in (`echo %*`) DO @ set params=%%j

Эта команда назначает 1-й параметр для «i», а остальные (обозначаемые «*») назначаются для «j», который затем используется для установки переменной «params».

10 голосов
/ 20 декабря 2013

Внимание! этот метод имеет побочный эффект расширения подстановочных знаков, если в аргументах есть «*» или «?». Если есть подстановочный знак, но нет соответствующих файлов, аргумент пропускается (не подстановочные аргументы остаются как есть). Если аргументы должны оставаться неизменными, ищите другой путь.


линия

%CMD% <WHAT DO I PUT HERE>

должен быть изменен на:

(
  SETLOCAL ENABLEDELAYEDEXPANSION
  SET skip=1

  FOR %%I IN (%*) DO IF !skip! LEQ 0 (
        SET "params=!params! %%I"
    ) ELSE SET /A skip-=1
)
(
  ENDLOCAL
  SET "params=%params%"
)
%CMD% %params%

конечно, вы можете установить skip var на любое количество аргументов.

объяснено:

(
@rem Starting block here, because it's read once and executed as one
@rem otherwise cmd.exe reads file line by line, which is waaay slower.

SETLOCAL ENABLEDELAYEDEXPANSION
SET skip=1

@rem if value contains unquoted non-paired parenthesis, SET varname=value 
@rem confuses cmd.exe. SET "a=value" works better even if value has quotes.
  FOR %%I IN (%*) DO (
    IF !skip! LEQ 0 (
      SET "params=!params! %%I"
      @rem newline after SET to lower amount of pitfalls when arguments 
      @rem have unpaired quotes
    ) ELSE (
      SET /A skip-=1
    )
)
(
@rem get variables out of SETLOCAL block
@rem as whole block in parenthesis is read and expanded before executing,
@rem SET after ENDLOCAL in same block will set var to what it was before
@rem ENDLOCAL. All other envvars will be reset to state before SETLOCAL.
ENDLOCAL
SET "params=%params%"
)
@rem doing this outside of parenthesis block to avoid
@rem cmd.exe confusion if params contain unquoted closing round bracket
%CMD% %params%
7 голосов
/ 02 октября 2013

Вы можете просто сделать это:

%*

Если это единственное в строке, то это расширяется тем, что первый параметр будет выполненной командой со всеми остальными параметрами, переданными ей. :)

1 голос
/ 11 апреля 2018

Я улучшил ответ Моше Горена, потому что он мне не помог:

set _input=%*
call set params=%%_input:%1 =%%
@echo %params%
1 голос
/ 20 декабря 2013

Другой способ (почти такой же, как у Алксандра Берда) без выполнения ECHO в подоболочке:

FOR /F "usebackq tokens=1*" %%I IN ('%*') DO SET params=%%J

итак, строка

%CMD% <WHAT DO I PUT HERE>

будет выглядеть так:

FOR /F "usebackq tokens=1*" %%I IN ('%*') DO %CMD% %%J

проблема в том, что если параметры включают в себя строки в кавычках с пробелами внутри, cmd.exe проанализирует их соответствующим образом для использования в качестве пронумерованных аргументов (% 1), но FOR проигнорирует кавычки. В этом конкретном случае будет вредно, если первый параметр содержит пробел или более, что вполне возможно, учитывая, что первым аргументом может быть, например, «C: \ Program Files \ Internet Explorer \ iexplore.exe».

Итак, здесь будет другой ответ.

0 голосов
/ 25 сентября 2017

Я сталкивался с этим вопросом, когда сталкивался с подобной проблемой, но решил ее другим способом. Вместо повторного создания строки ввода с использованием цикла (как в ответе @Joey) я просто удалил первый параметр из строки ввода.

set _input=%*
set params=!_input:%1 =!
call OTHER_BATCH_FILE.cmd %params%

Конечно, это предполагает, что все параметры разные.

0 голосов
/ 12 декабря 2014

Хотя решение «for» во многих случаях лучше, для чего-то простого я часто просто сохраняю и отвлекаю другие аргументы, затем использую %* как обычно (практически такая же стратегия часто работает для $* или $@ in {,ba,da,k,*}sh):

пример:

:: run_and_time_me.cmd - run a command with the arguments passed, while also piping
::                       the output through a second passed-in executable

@echo off

set run_me=%1
set pipe_to_me=%2
shift
shift

:: or
:: set run_me=%1
:: shift
:: set pipe_to_me=%1
:: shift

%run_me% %* | %pipe_to_me%

Как бы то ни было, я видел, что на вопрос давно дан ответ, но решил, что я уроню свои два цента, потому что это было что-то, чего я не видел, и потому что это был ответ, который мне был нужен, когда я, наконец, наткнулся на него несколько лет назад ... и пошел "о ... дух". :)

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