0

Can't work this out, I'm not hugely familiar with batch scripts although use them where I can.

I have a script that tests if the current file is larger then 4GB and to do on action if it is, and another action if not.

I have the following in a .bat file:

 %~d1

set fsize=%~z1

if %fsize% gtr 4000000000 (
    echo "exit"
) ELSE (
    echo "keep going"
)

pause

When I drag a 4.8 GB file onto this file, I get this result in command line:

set fsize=4876064456
if 4876064456 GTR 4000000000 (echo "exit" )  ELSE (echo "keep going" )
"keep going"

When I drag a 60 MB file onto it, I get this:

set fsize=61840920

if 61840920 GTR 4000000000 (echo "exit" )  ELSE (echo "keep going" )
"keep going"

If I change the operator to LSS, I get the "exit" result from both files instead. Why isn't it doing a proper comparison?

AutoBaker
  • 919
  • 2
  • 15
  • 31
  • 2
    I'm not sure where/if it's documented, but when the `EQU`, `NEQ`, `LSS`, `LEQ`, `GTR`, `GEQ` operators operate in numeric mode, the value is converted to a 32-bit signed int, meaning they act poorly if a number is above 2147483647 or below -2147483648 – Anon Coward Mar 05 '21 at 17:41
  • 1
    Technically the range is `-2,147,483,648` to `2,147,483,647`, (4 byte signed integer values). You can find a little more information [here](https://www.dostips.com/forum/viewtopic.php?f=3&t=3758). Essentially, you cannot use an integer as large as the one you've shown in your question. – Compo Mar 05 '21 at 18:07
  • If you provide a little more context, for instance exactly how you're passing the file as an input argument, (GUI or CLI), and what you're intending to do with it, we may be able to advise you on possible workarounds, otherwise your answer is, as the comments above. – Compo Mar 05 '21 at 18:58
  • Regards passing the file to the script, I have this saved as a .bat file, drag a video on to the batch file as mentioned and then the batch file opens and takes the file for it's parameter (hence the use of %~d1 and %~z1 to get current file details). – AutoBaker Mar 06 '21 at 20:02
  • @Compo would it work to divide both numbers by 1,000,000 and then do the comparison? – AutoBaker Mar 08 '21 at 10:13
  • no, an out-of-range number can not be used for arithmetic. What you could do is truncating it (snipping the last 6 digits: `set "fsize=%fsize:~0,-6%"` (when you can live with the inaccuracy) – Stephan Mar 08 '21 at 10:27
  • and it would also depend upon prior knowledge that your file was already larger than 1 MB, or less than 2 TB. – Compo Mar 08 '21 at 10:31
  • That's ok, I think I can work with that. Rough size is all I need in this case, I just need to split videos down into 2GB segments with ffmpeg and it won't matter if they're +/- a few MB. Will try it out – AutoBaker Mar 08 '21 at 10:34

3 Answers3

2
set "limit=4000000000"
set "zeroes=000000000000000000000000000000000000000000"

set "zlimit=%zeroes%%limit%"
set fsize=%zeroes%%~z1

if "%fsize:~-15%" gtr "%zlimit:~-15%" (...

The object here is to make the lengths of the two strings being compared equal by prefixing a goodly number of zeroes to each and then comparing the last (15) characters of each. Using strings because 4G exceeds the 32bit-signed capacity of cmd's integers.

Magoo
  • 77,302
  • 8
  • 62
  • 84
2

Depending upon how your providing the input argument, the following alternative may suit your purposes:

@Echo Off & SetLocal EnableExtensions
Set "Name=%~1"
%SystemRoot%\System32\wbem\WMIC.exe DataFile Where ^
 "FileSize <= '4294967296' And Name='%Name:\=\\%'" Get FileSize 2>NUL ^
 | %SystemRoot%\System32\find.exe "FileSize" 1>NUL || Echo Exit /B
Rem Your code here for files not greater than 4 Gibibytes

In the example above, I've used Gibibytes, which is what Windows Operating system tends to use for its file sizing. If you prefer to use Gigabytes, as in your provided example, please change 4294967296 to 4000000000 on line 4, and Gibibytes to Gigabytes on line 6.

Compo
  • 36,585
  • 5
  • 27
  • 39
1

The Windows command processor cmd.exe uses the C function strtol to convert a string to an integer for doing an integer comparison. The type long int is a 32-bit signed integer (not always, depends on C compiler, but for compilation of cmd.exe). For that reason the value range is limited to −2^31 to 2^31−1 which is −2147483648 to 2147483647.

This limitation can be worked around for checking if a file is ≥4294967296 as demonstrated by this code:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" echo ERROR: %~nx0 must be run with a file name.& goto EndBatch
if not exist "%~1" echo ERROR: File "%~1" not found.& goto EndBatch
if exist "%~1\" echo ERROR: "%~1" is not a file.& goto EndBatch

set "fsize=%~z1"
if "%fsize:~9,1%" == "" echo File is smaller than 4 GB.& goto EndBatch
if not "%fsize:~10,1%" == "" echo File is larger than 4 GB.& goto EndBatch
if "%fsize%" LSS "4294967296" echo File is smaller than 4 GB.& goto EndBatch
echo File is equal or larger than 4 GB.
:EndBatch
pause
endlocal

The first condition is true if the file size string has less than 10 characters which means the file size is less than 1000000000 bytes.

The second condition is true if the file size string has more than 10 characters which means the file size is greater than 9999999999 bytes.

The third condition is true if the file size string enclosed in double quotes with exactly 10 characters is less than the string "4294967296" which means the file size is less than 4294967296 bytes.

See the following answers for more information about string and integer comparisons:

Mofi
  • 46,139
  • 17
  • 80
  • 143