Подтвердить что ты не робот

Как заставить SHIFT работать с% * в пакетных файлах

В моем пакетном файле в Windows XP я хочу использовать %* для расширения до всех параметров, кроме первого.
Тестовый файл (foo.bat):

@echo off
echo %*
shift
echo %*

Вызов:

C:\> foo a b c d e f

Фактический результат:

a b c d e f
a b c d e f

Желаемый результат:

a b c d e f
b c d e f

Как я могу достичь желаемого результата? Спасибо!!

4b9b3361

Ответ 1

Не было бы замечательно, если бы CMD.EXE работал именно так! К сожалению, нет хорошего синтаксиса, который будет делать то, что вы хотите. Лучшее, что вы можете сделать, это проанализировать командную строку самостоятельно и создать новый список аргументов.

Что-то вроде этого может работать.

@echo off
setlocal
echo %*
shift
set "args="
:parse
if "%~1" neq "" (
  set args=%args% %1
  shift
  goto :parse
)
if defined args set args=%args:~1%
echo(%args%

Но вышеизложенное имеет проблемы, если аргумент содержит специальные символы, такие как ^, &, >, <, |, которые были экранированы вместо цитирования.

Обработка аргументов является одним из многих слабых аспектов пакетного программирования Windows. Для почти любого решения существует исключение, которое вызывает проблемы.

Ответ 2

Это легко:

setlocal ENABLEDELAYEDEXPANSION
  set "_args=%*"
  set "_args=!_args:*%1 =!"

  echo/%_args%
endlocal

То же самое с комментариями:

:: Enable use of ! operator for variables (! works as % after % has been processed)
setlocal ENABLEDELAYEDEXPANSION
  set "_args=%*"
  :: Remove %1 from %*
  set "_args=!_args:*%1 =!"
  :: The %_args% must be used here, before 'endlocal', as it is a local variable
  echo/%_args%
endlocal

Пример:

lets say %* is "1 2 3 4":

setlocal ENABLEDELAYEDEXPANSION
  set "_args=%*"             --> _args=1 2 3 4
  set "_args=!_args:*%1=!"   --> _args=2 3 4

  echo/%_args%
endlocal

Примечания:

  • Не работает, если какой-либо аргумент содержит! или или char
  • Любые дополнительные пробелы между аргументами НЕ удаляются

Ответ 3

Не думайте, что есть простой способ сделать это. Вместо этого вы можете попробовать играть со следующим обходным решением:

@ECHO OFF
>tmp ECHO(%*
SET /P t=<tmp
SETLOCAL EnableDelayedExpansion
IF DEFINED t SET "t=!t:%1 =!"
ECHO(!t!

Пример:

test.bat 1 2 3=4

Вывод:

2 3=4

Ответ 4

Мне пришлось сделать это недавно и придумали это:

setlocal EnableDelayedExpansion

rem Number of arguments to skip
set skip=1

for %%a in (%*) do (
  if not !position! lss !skip! (
    echo Argument: '%%a'
  ) else (
    set /a "position=!position!+1"
  )
)

endlocal

Он использует цикл для пропускания первых аргументов N. Может использоваться для выполнения некоторой команды для каждого аргумента или для создания нового списка аргументов:

setlocal EnableDelayedExpansion

rem Number of arguments to skip
set skip=1

for %%a in (%*) do (
  if not !position! lss !skip! (
    set args=!args! %%a
  ) else (
    set /a "position=!position!+1"
  )
)

echo %args%

endlocal

Обратите внимание, что приведенный выше код добавит ведущее пространство к новым аргументам. Его можно удалить следующим образом:

Ответ 5

Еще один простой способ сделать это:

set "_args=%*"
set "_args=%_args:* =%"

echo/%_args%

Примечания:

  • Не работает, если первый аргумент (% 1) "цитируется" или "двойной кавычек"
  • Не работает, если какой-либо аргумент содержит и char
  • Любые дополнительные пробелы между аргументами НЕ удаляются

Ответ 6

Возобновить все и исправить все проблемы:

set Args=%1
:Parse
shift
set First=%1
if not defined First goto :EndParse
  set Args=%Args% %First%
  goto :Parse
:EndParse

Не поддерживать пробелы между аргументами: 1 2 3 4 будет 1 2 3 4

Ответ 7

Еще один неприятный недостаток пакетного программирования для DOS/Windows...

Не уверен, что это на самом деле лучше, чем некоторые другие ответы здесь, но думал, что поделюсь чем-то, что, кажется, работает для меня. Это решение использует циклы FOR, а не goto, и содержится в пакетном скрипте многократного использования.

Отдельный пакетный скрипт "shiftn.bat":

@echo off
setlocal EnableDelayedExpansion
set SHIFTN=%1
FOR %%i IN (%*) DO IF !SHIFTN! GEQ 0 ( set /a SHIFTN=!SHIFTN! - 1 ) ELSE ( set SHIFTEDARGS=!SHIFTEDARGS! %%i ) 
IF "%SHIFTEDARGS%" NEQ "" echo %SHIFTEDARGS:~1%

Как использовать shiftn.bat в другом пакетном скрипте; в этом примере получение всех аргументов после первого (пропущенного) аргумента:

FOR /f "usebackq delims=" %%i IN ('call shiftn.bat 1 %*') DO set SHIFTEDARGS=%%i 

Возможно, кто-то другой может использовать некоторые аспекты этого решения (или предложить предложения по улучшению).