Windows CMD Batch for 循环中如何处理带括号的文件名?

问题描述 投票:0回答:2

我想编写一个脚本,将掉落在其上的文件移动到某个地方。这就是我的批处理代码的运行方式:

@echo off
for %%i in (%*) do move "%%~i" "somewhere\%%~nxi"
pause

然后我发现,当我删除一个名称为 包含 ')' 且不包含空格的文件时(例如

fig(1).jpg
,它会报告一个错误,提示“不应有 .jpg” ”.

我知道直接在终端中写

./xxx.bat "fig(1).jpg"
就可以了,但我确实需要在上面放置一些文件。有什么帮助吗?

batch-file cmd special-characters movefile
2个回答
0
投票

请改用 PowerShell。只需将其另存为

move-to-somewhere.ps1

ls $args | mv -d "somewhere"

然后创建一个新的快捷方式并粘贴它

powershell.exe -noprofile -noexit -f path\to\move-to-somewhere.ps1

现在只需将您想要的文件拖到新创建的快捷方式中,它们就会按预期移动

完整的命令是

Get-ChildItem -LiteralPath $args | Move-Item -Destination "somewhere"
,您还可以附加
-WhatIf
/
-wi
在实际移动文件之前进行试运行

事实上它应该更容易,但由于某种原因,直接在 *.ps1 文件上拖放文件的方法不起作用,最简单的临时解决方法是使用快捷方式。您还可以创建一个批处理文件并将所有参数转发到 PowerShell,但文件内容会略有不同。有关更多信息以及其他方法,请阅读


0
投票

该错误是由

FOR
发出的,它对特殊字符的转义要求比文件名规则更严格。

您不能引用

%*
,因为解释器不会将
%*
视为可以迭代的列表,而是将它们视为由编号参数组成的单个字符串,因为它们被传递给脚本。
FOR
自己对该字符串的处理导致了您所看到的错误。

值得庆幸的是,您在

FOR
变量中使用的字符串操作功能也可用于编号参数(
%1
%2
等),因此您不必在解析错误的列表上循环,而是可以使用真实的(参数)列表并使用
:label
GOTO
:

进行迭代
@ECHO OFF

:loop_args
IF NOT "{%~1}"=="{}" (
  MOVE "%~1" "somewhere\%~nx1"
  SHIFT
  GOTO :loop_args
)

本质上,第一个参数

%~1
始终不为空,我们执行三个操作:

  1. 将文件移动到其字符串操作的路径
  2. 将第一个参数从列表中弹出(将第二个参数移至第一个,第三个移至第二个,依此类推)
  3. 返回标签

当没有更多参数时,第一个参数变为空,因此解释器将继续执行右括号

)
后面的下一条语句,或者如果没有更多语句则退出。

请注意,您可以写这个简写,如果它对您来说更好的话,通过用

&
分隔三个命令:

:loop_args
IF NOT "{%~1}"=="{}" ( MOVE "%~1" "somewhere\%~nx1" & SHIFT & GOTO :loop_args )

如果您的动作比简单的动作更复杂,请使用另一个标签将您的动作放在自己的“函数”中:

@ECHO OFF
SETLOCAL 

:::: MAIN LOGIC ::::

ECHO Starting with arguments: %*
ECHO.

:loop_args
IF NOT "{%~1}"=="{}" ( CALL :do_something "%~1" & SHIFT & GOTO :loop_args )

ECHO.
ECHO Finished processing %NUM_CALLS% argument(s)

ENDLOCAL
GOTO :EOF

:::: FUNCTIONS ::::

:do_something
  IF DEFINED NUM_CALLS (
    ECHO.
    ECHO.******* 
    ECHO.
    SET /a NUM_CALLS += 1
  ) ELSE (
    SET NUM_CALLS=1
  )

  ECHO You passed the value ^[ %1 ^]
  ECHO Unquoted, this reads ^[ %~1 ^]
  ECHO This resolves to the file: %~f1
  ECHO Here is just the filename: %~n1
  ECHO Here is it's extension: %~x1
  ECHO How about a size, too^?: %~z1

  IF EXIST "%~f1" (
    ECHO Here is where it lives... 
    DIR "%~dp1"
  )
GOTO :EOF

当您

CALL
一个函数时,您可以向它传递参数,解释器会将这些参数存储在自己的一组编号变量中,并且您可以像操作
FOR
变量一样操作它们。当函数完成时,您将返回调用者中拥有的编号变量。

与单个

IF
语句不同,您可以操作函数内的环境变量。这些更改对于脚本来说是全局的,除非您在函数开头调用
SETLOCAL
并在函数末尾调用
ENDLOCAL

请注意

GOTO :EOF
的使用,这是一个特殊标签,如果您当前未运行函数,则标记函数的结束 脚本的结束。特别要注意主逻辑和函数之间的一个——这会阻止解释器在完成主例程后运行函数内的代码。

对于这两种方法,还要注意,您只能迭代参数列表一次,因为一旦每个参数被

SHIFT
从列表中删除,它就消失了。如果您想保留它们,您需要采用不同的数组技术,但这是另一个问题的问题。

© www.soinside.com 2019 - 2024. All rights reserved.