【问题标题】:Getting function parameters gets command line parameters - batch获取函数参数获取命令行参数-批处理
【发布时间】:2017-03-16 21:28:51
【问题描述】:

我将命令行参数传递给批处理脚本并将其设置为如下变量:

SET dirWhereKept=%1

我的问题是,我在批处理脚本中调用了一个带有 3 个参数的函数。当尝试获取这 3 个参数时,它会改为通过命令行获取传入的参数:

FOR /f "delims=" %%i IN ('DIR /B') DO (
    IF EXIST "%%~i\" (
        rem nothing
    ) ELSE (
        CALL :checkIfWantedFile %%i "%%~xi" %%~zi
    )
)

:checkIfWantedFile
SET file=%~1
SET fileExtension=%~2
SET fileSizeInBytes=%~3

ECHO FILE: %file%
ECHO EXTENSION: %fileExtension%
ECHO SIZE: %fileSizeInBytes%

例如,如果我将"Avatar ECE (2009)" 作为命令行参数(它是一个目录)传递,然后在调用函数时我传递:

  • %%i: Avatar.mp4
  • "%%~xi": ".mp4"
  • %%~zi: some_int

当我在checkIfWantedFile 中执行ECHO 时,输出将是:

FILE: Avatar ECE (2009)
EXTENSION:
SIZE:

因为它获取的是命令行参数而不是函数参数。

我查看了 this 和其他一些,但无法使其正常工作。

编辑:

此批处理脚本的目的是进入给定目录(由命令行参数提供)并提取和视频文件(.mp4.mkv.avi)也许在里面。有时,视频文件嵌套在子目录中,这就是为什么我要检查FOR 循环中的项目是否是文件夹。如果是,那么批处理脚本打算进入子目录并检查那里是否有任何想要的视频文件并提取它们。

我添加了一个选项,即如果脚本遇到不需要的文件,则会将其删除。但这不是必需的。

意图也是当目录(在命令行参数中提供)递归地清除所有视频文件时,它被删除。

由于有时会出现不需要的视频示例文件,我还检查了文件的大小(以 MB 为单位),如果是 GTR 然后是 %minimumSize% 那么它是一个想要的文件并且可以被提取

我的完整代码如下:

@ECHO off

SET "dirWhereKept=%1"
SET mp4=".mp4"
SET mkv=".mkv"
SET avi=".avi"
SET needCompressingDir="E:\Need_compressing"
SET minimumSize=200

CD %needCompressingDir%
CD %dirWhereKept%
FOR /f "delims=" %%i IN ('DIR /B') DO (
    IF EXIST "%%~i\" (
        rem do nothing
    ) ELSE (
        GOTO :EOF
        CALL :checkIfWantedFile "%%i" "%%~xi" "%%~zi"
    )
)

:checkIfWantedFile
SET file=%~1
SET fileExtension=%~2
SET fileSizeInBytes=%~3

IF "%fileExtension%" == %mp4% (
    CALL :checkFileSize %fileSizeInBytes%
) ELSE (
    IF "%fileExtension%" == %mkv% (
        CALL :checkFileSize %fileSizeInBytes%
    ) ELSE (
        IF "%fileExtension%" == %avi% (
            CALL :checkFileSize %fileSizeInBytes%
        ) ELSE (
            rem this is not required!
            CALL :deleteFile
        )
    )
)

:checkFileSize
SET /a fileSizeInMB=%~1/1024/1024

IF %fileSizeInMB% GTR %minimumSize% (
    CALL :moveFileToCompress
)

:deleteFile
ECHO "Delete called!"

:moveFileToCompress
MOVE %file% %needCompressingDir%

【问题讨论】:

  • 始终正确使用引号:将SET dirWhereKept=%1 更改为SET "dirWhereKept=%~1",因此引号不会成为变量值的一部分,但可以防止行因特殊字符而失败;然后将%%i改为"%%~i"等; ~ 删除潜在的引号;与显式 "" 一起,这确保了值周围始终存在一对 ""...

标签: batch-file


【解决方案1】:

将CALL语句中的%%i改为"%%i"

示例:

@ECHO OFF
SET "dirWhereKept=%~1"
IF /I NOT "%CD%"=="%~1" PUSHD "%~1"2>Nul||Exit/B
FOR %%i IN (*.*) DO CALL :checkIfWantedFile "%%i" "%%~xi" "%%~zi"
TIMEOUT -1
EXIT/B

:checkIfWantedFile
ECHO FILE: %~1
ECHO EXTENSION: %~2
ECHO SIZE: %~3

【讨论】:

  • 仍然得到相同的结果
  • 你不可能得到同样的结果!在您的示例中,您传递了五个参数“%~1=Avatar, %~2=ECE, %~3=(2009), %~4=.mp4, %~5=some_int”,我的正在传递“%~1 =阿凡达 ECE (2009), %~2=.mp4, %~3=some_int"
  • 我发现了一个错误。在检查当前项目是否为文件夹时,如果项目 not 是文件夹,则它不会进入else 条件,因此永远不会调用该函数。但是如果函数从来没有被调用过,为什么会被调用呢?
  • 看看我提供的示例,它没有看到“文件夹”,因此不需要条件。调用您的函数是因为在 checkIfWantedFile 标签之前没有什么可以告诉您的代码停止
  • 我需要检查该项目是否为文件夹。如果是,我需要检查其中的文件是否感兴趣。所以,基本上,递归地遍历子目录
【解决方案2】:

您的问题只是批处理没有sectionprocedure 的概念。它只是执行下一条语句,直到到达文件结尾或exit

因此,call 执行例程:checkIfWantedFile,当它到达文件末尾时,它返回到call 之后的下一个逻辑语句——即例程:checkIfWantedFile,因此它继续执行,使用提供给批处理本身的参数作为%n

您需要在:checkIfWantedFile 标签之前插入goto :eof 行,以便在call 执行后跳过例程。请注意,:eof 中的冒号很关键。 :eofcmd 定义为文件结尾。


您正在call处理许多子例程。您需要在 each 和每个 子例程的末尾特别指定 goto :eof,否则批处理只会继续逐行执行。比如

:deleteFile
ECHO "Delete called!"

:moveFileToCompress
MOVE %file% %needCompressingDir%

如果你 call :deletefile 则执行回显,并尝试 move

如果您是call :moveFileToCompress,那么只会尝试move

如果你把它改成

:deleteFile
ECHO "Delete called!"

GOTO :EOF

:moveFileToCompress
MOVE %file% %needCompressingDir%

goto :eof

然后
如果你call :deletefile 则执行回显。

如果您 call :moveFileToCompress 则尝试 move

当然,文件末尾的goto :eof 是多余的。我习惯使用它,所以我不需要记住在新添加的例程之前插入它以防止流过。

您需要为call 的每个子例程遵循类似的模式。

当我说“报告”时,我的意思是批处理 echoes 到控制台,所以在你的代码中

:checkIfWantedFile
SET file=%~1
SET fileExtension=%~2
SET fileSizeInBytes=%~3

ECHO FILE: %file%
ECHO EXTENSION: %fileExtension%
ECHO SIZE: %fileSizeInBytes%

这将设置变量,然后报告它们的值。

(顺便说一句 - 你可能喜欢使用

set file

用于报告这些值,这将显示以 file 开头的每个现有变量的值和名称 - 输入更少...)

【讨论】:

  • 放置GOTO :EOF 会完全终止批处理脚本。有没有办法让它转到FOR 循环中的下一个项目?
  • 它会遍历目录中的所有项目(文件名和目录名),如果找到的名称为.\namefound,则不执行任何操作并在设置变量后报告,然后继续下一个。当它到达末尾时,它将终止(如果goto :eof),变量设置为最后匹配的报告名称。也许如果您要清楚地解释您的意图是什么,我们可以建议一种适当的方法。事实上,我们只有你的代码——我们可以分析那个,但我们需要一个水晶球来探知你执行代码的原因。
  • 谢谢!我对设置变量和报告的意思感到困惑吗?我将编辑我的问题,以便您清楚地了解我要做什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2014-01-03
  • 2018-06-14
  • 2011-01-12
  • 2023-03-11
  • 2014-02-15
相关资源
最近更新 更多