Как заставить 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
Как я могу достичь желаемого результата? Спасибо!!
Ответы
Ответ 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
Возможно, кто-то другой может использовать некоторые аспекты этого решения (или предложить предложения по улучшению).