我想编写一个脚本,将掉落在其上的文件移动到某个地方。这就是我的批处理代码的运行方式:
@echo off
for %%i in (%*) do move "%%~i" "somewhere\%%~nxi"
pause
然后我发现,当我删除一个名称为 包含 ')' 且不包含空格的文件时(例如
fig(1).jpg
),它会报告一个错误,提示“不应有 .jpg” ”.
我知道直接在终端中写
./xxx.bat "fig(1).jpg"
就可以了,但我确实需要在上面放置一些文件。有什么帮助吗?
请改用 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,但文件内容会略有不同。有关更多信息以及其他方法,请阅读
该错误是由
FOR
发出的,它对特殊字符的转义要求比文件名规则更严格。
您不能引用
%*
,因为解释器不会将 %*
视为可以迭代的列表,而是将它们视为由编号参数组成的单个字符串,因为它们被传递给脚本。 FOR
自己对该字符串的处理导致了您所看到的错误。
值得庆幸的是,您在
FOR
变量中使用的字符串操作功能也可用于编号参数(%1
、%2
等),因此您不必在解析错误的列表上循环,而是可以使用真实的(参数)列表并使用 :label
和 GOTO
: 进行迭代
@ECHO OFF
:loop_args
IF NOT "{%~1}"=="{}" (
MOVE "%~1" "somewhere\%~nx1"
SHIFT
GOTO :loop_args
)
本质上,第一个参数
%~1
始终不为空,我们执行三个操作:
当没有更多参数时,第一个参数变为空,因此解释器将继续执行右括号
)
后面的下一条语句,或者如果没有更多语句则退出。
请注意,您可以写这个简写,如果它对您来说更好的话,通过用
&
分隔三个命令:
: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
从列表中删除,它就消失了。如果您想保留它们,您需要采用不同的数组技术,但这是另一个问题的问题。