@echo off
for /f "tokens=1,2 delims=," %%x in (my.csv) do (
if %M% LSS %%x set M=%%x
)
echo Max X Value= %M%
Иногда работает нормально, иногда вылетает со следующей ошибкой:
%x was unexpected at this time.
@echo off
for /f "tokens=1,2 delims=," %%x in (my.csv) do (
if %M% LSS %%x set M=%%x
)
echo Max X Value= %M%
Иногда работает нормально, иногда вылетает со следующей ошибкой:
%x was unexpected at this time.
Проблема в том, что вы используете %m%
внутри цикла for
. Это оценивается, когда цикл читается (до каких-либо итераций вообще). Другими словами, весь цикл, включая закрывающую скобку, считывается и оценивается перед выполнением. Таким образом, %m%
всегда будет начальным значением, независимо от того, что вы на самом деле установили в цикле.
Пример должен, надеюсь, проиллюстрировать это:
set val=7
for %%i in (1) do (
set val=99
echo %val%
)
echo %val%
что приводит к неожиданному (для некоторых):
7
99
просто потому, что %val%
в первом операторе echo интерпретируется (т. е. весь цикл for
интерпретируется) до того, как любой из них будет запущен.
Вам нужно отложенное расширение вместе с чем-то, что заставит значение m
быть установлено на первое %%x
независимо. Использование команды setlocal
и !m!
вместо %m%
будет откладывать вычисление m
до тех пор, пока не будет выполняться строка каждый раз.
Кроме того, установка m
изначально равным нулю и принудительное присвоение ему значения %%x
, когда оно ничего, гарантирует, что первое значение %%x
будет загружено в m
.
@echo off
setlocal enableextensions enabledelayedexpansion
set m=
for /f "tokens=1,2 delims=," %%x in (my.csv) do (
if "!m!" == "" set m=%%x
if !m! lss %%x set m=%%x
)
echo Max X Value = !m!
endlocal
Используя приведенный выше код с этим файлом my.csv
:
1,a
2,b
10,c
3,d
приводит к выводу:
Max X Value = 10
как и ожидалось, или для ваших образцов данных в другом комментарии:
422,34
464,55
455,65
421,88
ты получаешь:
Max X Value = 464
Переменная окружения с именем M
не установлена, поэтому при интерпретации этой строки:
if %M% LSS %%x set M=%%x
После 1-го раунда замен он выглядит для переводчика примерно так
if LSS %x set M=%x
Чтобы избежать проблем, о которых упоминает paxdiablo %M%
расширяется только тогда, когда цикл первый, вы можете использовать функцию отложенного расширения, которую он обсуждает, или переместить тестирование и настройку M
в подпрограмму, которая вызывается из цикла, но существует вне цикла, поэтому она интерпретируется (и расширяется) при каждом вызове. :
@echo off
set M=
for /f "tokens=1,2 delims=," %%x in (my.csv) do (
call :setmax %%x
)
echo Max X Value= %M%
goto :eof
:setmax
if "%M%" == "" set M=%1
if %M% LSS %1 set M=%1
goto :eof
M
не будет установлено ничего до запуска сценария. Если для переменной M
уже установлено что-то, эта ошибка не возникнет (хотя может возникнуть другая ошибка, если для M
установлено что-то, что снова делает команду синтаксически неправильной)
- person Michael Burr; 03.02.2010
LSS
работает со строками (или, может быть, целыми числами или строками). Как я уже говорил в другом месте, пакетные файлы очень плохо справляются со сложной обработкой данных (при очень малом значении комплексности). Я уверен, что эту проблему можно решить, но тогда будет какая-то другая странность пакетных сценариев, из-за которой она падает, когда ваши данные слегка изменяются. Я бы предложил использовать другой инструмент, но если вы настаиваете на использовании пакетных сценариев для этих вещей, возьмите замечательную книгу Тима Хилла по этому вопросу (у продавца, бывшего в употреблении, она может быть очень дешевой): amazon.com/dp/1578700477
- person Michael Burr; 04.02.2010
Проблема в вашем заявлении if %M%
. Где находится %М%? объявите это первым, например
@echo off
set M=""
for /f "tokens=1,2 delims=," %%x in (file) do (
if %M% LSS %%x set M=%%x
)
echo Max X Value= %M%
В качестве альтернативы вы можете использовать vbscript
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objArgs = WScript.Arguments
strFile = objArgs(0)
Set objFile = objFS.OpenTextFile(strFile)
t=0
Do Until objFile.AtEndOfStream
linenum = objFile.Line
strLine = objFile.ReadLine
s = Split(strLine,",")
For Each num In s
WScript.Echo "num "&num
If Int(num) >= t Then
t=Int(num)
End If
Next
WScript.Echo "Max for line:" & linenum & " is " & t
Loop
пример вывода
C:\test>type file
422,34464,55455,65421,88
C:\test>cscript //nologo test.vbs file
Max for line:1 is 65421
ОБНОВЛЕНИЕ: Чтобы найти столбец максимального значения
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objArgs = WScript.Arguments
strFile = objArgs(0)
Set objFile = objFS.OpenTextFile(strFile)
t=0
Do Until objFile.AtEndOfStream
linenum = objFile.Line
strLine = objFile.ReadLine
s = Split(strLine,",")
If Int(s(0)) >= t then
t=Int(s(0))
End If
Loop
WScript.Echo "Max is " & t & " (line: " & linenum & ")"
вывод
C:\test>type file
422,34
464,55
455,65
421,88
C:\test>cscript //nologo test.vbs file
Max is 464 (line: 2)