1 (изменено: Rumata, 2011-12-15 00:52:52)

Тема: CMD/BAT: Странная совместная работа SHIFT + IF

Два скрипта, одна логика и разные результаты
Скрипт 1 (bug1.bat)

@echo off

if not "%~1" == "A" goto not_A

set BUG_A=1
shift /1

if not "%~1" == "B" goto not_B

set BUG_B=1
shift /1

:not_B

set BUG_C=1

:not_A

set BUG

.
Скрипт 2 (bug2.bat)


@echo off

if "%~1" == "A" (
	set BUG_A=1
	shift /1
	if "%~1" == "B" (
		set BUG_B=1
		shift /1
	)
	set BUG_C=1
)

set BUG

.
А теперь запустим их:

C:\tmp>bug1 A
BUG_A=1
BUG_C=1

C:\tmp>bug1 A B
BUG_A=1
BUG_B=1
BUG_C=1

C:\tmp>bug2 A
BUG_A=1
BUG_C=1

C:\tmp>bug2 A B
BUG_A=1
BUG_C=1

Мне не понятно, почему во втором скрипте SHIFT /1 не влияет на проверяемый аргумент во втором сравнении. Чтобы исправить проблему приходится писать так (вот втором и третьем скриптах различие только во втором сравнении):
Скрипт 3 (bug3.bat)


@echo off

if "%~1" == "A" (
	set BUG_A=1
	shift /1
	if "%~2" == "B" (
		set BUG_B=1
		shift /1
	)
	set BUG_C=1
)

set BUG

.
Тогда логика верна:

C:\tmp>bug3 A
BUG_A=1
BUG_C=1

C:\tmp>bug3 A B
BUG_A=1
BUG_B=1
BUG_C=1

( 2 * b ) || ! ( 2 * b )

2 (изменено: Smitis, 2011-12-23 23:55:02)

Re: CMD/BAT: Странная совместная работа SHIFT + IF

Получается, скобки действуют на параметры так же, как и на переменные среды. Потому что за скобками оказывается, что все команды shift внутри скобок отработали.

3 (изменено: smaharbA, 2011-12-26 20:02:02)

Re: CMD/BAT: Странная совместная работа SHIFT + IF

отложенная обработка
Вы бы еще call :метка выполнили и удивлялися

Я конечно далек от мысли... (с)

4

Re: CMD/BAT: Странная совместная работа SHIFT + IF

smaharbA пишет:

отложенная обработка

Эммм... Вы об чем? Какая может быть отложенная обработка? Два скрипта - первый и второй, одна логика, разный результат. О какой отложенной обработке в условных операторах может идти речь?

( 2 * b ) || ! ( 2 * b )

5

Re: CMD/BAT: Странная совместная работа SHIFT + IF

никакой в блоках

Я конечно далек от мысли... (с)

6

Re: CMD/BAT: Странная совместная работа SHIFT + IF

smaharbA
Коллега, выражайте свои мысли более развернуто. Сложно понять Ваши тезисы в контексте настоящей задачи.

( 2 * b ) || ! ( 2 * b )

7 (изменено: smaharbA, 2011-12-27 10:50:11)

Re: CMD/BAT: Странная совместная работа SHIFT + IF

@echo off
call :test "%%~1" == "A" && (
    set BUG_A=1
    shift /1
    call :test "%%~1" == "B" && (
        set BUG_B=1
        shift /1
    )
    set BUG_C=1
)
set BUG
exit /b

:test
setlocal
shift
endlocal & if not %* exit /b 1

поправочка

Я конечно далек от мысли... (с)

8

Re: CMD/BAT: Странная совместная работа SHIFT + IF

smaharbA
О боже! Магия. Но все абсолютно нелогично - в блоках с IF не работает, в блоках с call :label - работает. Ваш ответ поверг меня в шок.

( 2 * b ) || ! ( 2 * b )

9

Re: CMD/BAT: Странная совместная работа SHIFT + IF

Как всё запутанно...
После нового года и не разобраться

Вообще, у командного процессора сдесь срабатывают такие основные принципы, imho:
- Принцип подстановки значений переменных - сначала считывается строка, затем значения переменных подставляются в строку, затем строка выполняется. Переменные среды в командном процессоре в большей степени это макроподстановки, а не переменные, как они понимаются в других языках.
- Скобки как бы объединяют несколько строк в блок, который обрабатыватся как единое целое. Т.е. помимо первой считанной строки командный процессор считывает все остальные до строки, содержащей закрывающую скобку (с учётом вложений), подставляет переменные, выполняет этот блок.

10

Re: CMD/BAT: Странная совместная работа SHIFT + IF

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

Хотя Вы правы:

Smitis пишет:

Получается, скобки действуют на параметры так же, как и на переменные среды

Smitis пишет:

<...> Скобки как бы объединяют несколько строк в блок, который обрабатыватся как единое целое <...>

( 2 * b ) || ! ( 2 * b )

11

Re: CMD/BAT: Странная совместная работа SHIFT + IF

Возвращаюсь к своей же теме. Все очень и очень плохо.

Батник - это какое-то недоразумение. Боролся со скобками. Это была Пиррова победа. Батник - не шелл. Далеко не шелл. Хотя в последнем-то своих трудностей и своеобразностей хватает, но большинство их хорошо документировано и описано на многих ресурсах.

Мне надо было реализовать нечто, что описывается примерно так:

script.bat [/x [/a] [/b] [/c]] другие параметры

Или словесно: если указана опция /x, то допустимы одна из опций /a, /b, или /c, или их комбинация, но только в указанной последовательности.

Проблема решается только если использовать явные переход с помощью IF ... GOTO.

( 2 * b ) || ! ( 2 * b )

12

Re: CMD/BAT: Странная совместная работа SHIFT + IF

Rumata пишет:

…или их комбинация, но только в указанной последовательности.

То есть:

script.bat /x /c /a

— недопустимо?

13 (изменено: Rumata, 2012-02-24 21:07:10)

Re: CMD/BAT: Странная совместная работа SHIFT + IF

alexii, уже - да. В идеале хотелось бы решить более универсально и разрешить произвольный порядок аргументов, но тогда алгоритм усложняется. Оригинал выглядит так:


script.bat [/x [/a "string_a"] [/b "string_b"] [/c "string_c"]] другие параметры

Я же намеренно упростил пример.

( 2 * b ) || ! ( 2 * b )

14

Re: CMD/BAT: Странная совместная работа SHIFT + IF

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

:optexist (options) {
    @@rem Процедура поиска указанного параметра в командной строке скрипта
    @@rem
    setlocal
    set opt=%~1
rem    set arg=%opt:*:=%
    :loop_optexist
    shift
    if /i "%opt%"=="%~1" (
        exit /b 0
        ) else if "%~1"=="" (
        exit /b 1
        )
    goto loop_optexist
    endlocal
    exit /b 2
    }

:getopts (options) {
    @@rem Процедура получения всех параметров командной строке скрипта
    @@rem (не используется)
    @@rem
    setlocal
    :loop_getopts
    set value=
    set opt=%~1
    if "%opt:~0,1%"=="/" (
        set opt=%opt:~0,2%
        set value=%opt:~2%
        ) else if "%opt:~0,1%"=="-" (
        set opt=%opt:~0,2%
        set value=%opt:~2%
        ) else if "%~1"=="" (
        exit /b
        ) else (
        set value=%opt%
        set opt=
    )
    if "%value%"=="" (
        set value=%~2
        if "%value:~0,1%"=="/" (
            set value=
            ) else if "%value:~0,1%"=="-" (
            set value=
            ) else (
            shift
            )
        )
    shift
    echo set opt=%opt%^|set value=%value%
    goto loop_getopts
    endlocal
    exit /b
}

:optskip () {
    @@rem Процедура пропуска указанного параметра в командной строке скрипта
    @@rem (не используется)
    @@rem
    setlocal
    set ret=%~1
    set optskip=%~2
    :loop_optskip
    set opt=%~3
    if "%opt:~0,1%"=="%optskip%" (
        shift
        goto loop_optskip
        )
    endlocal & set %ret%=%3 %4 %5 %6 %7 %8 %9
    exit /b
    }
Я конечно далек от мысли... (с)

15

Re: CMD/BAT: Странная совместная работа SHIFT + IF

Неправильно делаете.
Всё сводится к простому* поиску подстроки в строке.
Как-то так:

@REM Разбор произвольно расположенных аргументов 
@ECHO OFF
@SETLOCAL EnableDelayedExpansion EnableExtensions

:MAIN
    set params=%*
    IF NOT DEFINED params (exit/b)
    SET "KEYS="/A ",/B,/C,/D,/X,/register,/etc"
    FOR %%R IN (%KEYS%) DO    (
        IF /i NOT  "!params:%%~R=!"=="%params%" (
            echo. ЇаЁбгвбвўгҐв Є«оз  [%%~R]
            REM здесь уже в зависимости от аргумента выполняем разбор, ala «SELECT CASE»:
            REM if "%%~R"=="/A" (…)
            REM if "%%~R"=="/B" (…)
            
            REM …или же просто:
            CALL :%%~R 2>nul
            )
        )
exit/b

:/A
        echo  parsing for /A, and analysis input parameters
exit/b

:/C
        echo PARSE FOR /C
exit/b
…

:/X
        echo PARSE FOR /X 
exit/b

>params.bat /A /B /C
присутствует ключ  [/A ]
parsing for /A, and analysis input parameters
присутствует ключ  [/b]
присутствует ключ  [/C]
PARSE FOR /C

>params.bat /x /a /C
присутствует ключ  [/A ]
parsing for /A, and analysis input parameters
присутствует ключ  [/C]
PARSE FOR /C
присутствует ключ  [/X]
PARSE FOR /X

* - да, возможно тема никогда и не затрагивалась на форуме

16

Re: CMD/BAT: Странная совместная работа SHIFT + IF

Пришлось побороться с этой магией скобок, кавычек. Следующий код допускает такие комбинации аргументов:


script.bat filename другие параметры
script.bat /x "string_x" другие параметры
script.bat /x [/a "string_a"] [/b "string_b"] [/c "string_c"] другие параметры

Дайте знать, если это не так.


@echo off

setlocal enabledelayedexpansion

if /i "%~1" == "/x" goto X1

	set X1_line=
	set X1_more=
	set X1_opt=%~1
	if defined X1_opt if not exist "!X1_opt!" (
		echo.File not found "!X1_opt!".

		endlocal
		exit /b 1
	)
	shift /1

goto X2
:X1

	set X1_line=1
	set X1_more=

:X1_again

	for %%k in ( a b c ) do (
		if /i "%~2" == "/%%~k" (
			set X1_more=1
			set X1_opt_%%~k=%3
			shift /1
			shift /1
			goto X1_again
		)
	)

	if not defined X1_more (
		set X1_opt=%2
		shift /1
	)

	shift /1

:X2

set X1
( 2 * b ) || ! ( 2 * b )