如何正确地嵌套两个`forfiles`循环(以便内部体扩展两个迭代级别的变量)? [英] How to nest two `forfiles` loops properly (so that the inner body expands variables of both iteration levels)?
问题描述
我正在尝试嵌套两个 forfiles
循环,以便内部循环的命令从两个都接收到 @
变量外循环和内循环迭代。对于后者,需要为外部循环转义 @
变量替换,以便内部 forfiles
命令接收变量
I am trying to nest two forfiles
loops so that the command of the inner loop receives @
variables from both the outer and the inner loop iteration. For the latter the @
variable replacement needs to be escaped for the outer loop so that the inner forfiles
command receives the variable name.
我有一个代码片段,枚举给定的目录( C:\root
),如果迭代的项目是自己的目录,则列出所有包含的文本文件( *。txt
)。
但是,它不起作用如预期的那样:我试图逃避 @file
与 \
的扩展,但它扩展到外部循环:
I have got a code snippet that enumerates a given directory (C:\root
), and if the iterated item is a directory on its own, all the contained text files (*.txt
) are listed.
However, it does not work as expected: I tried to escape the expansion of @file
with \
, but it expands to the value of the outer loop:
2> nul forfiles /P "C:\root" /M "*" /C "cmd /C if @isdir==TRUE forfiles /P @path /M *.txt /C \"cmd /C echo @relpath -- \@file\""
除了 \ @ file
,还 ^ @ file
, ^^ @ file
, ^ ^^ @ file
, 0x40file
( 0x40
是十六进制字符代码的 @
)扩展为外部 forfile
变量的值。
\\\ @文件
和 ^^^^ @ file
展开为外部值,使用 \
和 ^
分别。
即使 @ ^ file
, @ ^^文件
(请参阅此帖)不起作用(后者扩展到 @file
字面上)。
Besides \@file
, also ^@file
, ^^@file
, ^^^@file
, 0x40file
(0x40
being the hexadecimal character code representation of @
) expand to the value of the outer forfiles
variable.
\\@file
and ^^^^@file
expand to the outer value too, with \
and ^
preceeded, respectively.
Even @^file
, @^^file
(see this post) does not work (the latter expands to @file
literally).
所以:有没有办法逃避更换 @
变量(如 @file
,...)从外部 forfile
forfiles iteration接收文字变量名称并将其扩展为其值?
So: is there a way to escape the replacement of @
variables (like @file
,...) from the outer forfiles
loop so that the inner forfiles
iteration receives the literal variable name and expands it to its value?
我在Windows 7上工作64位。
I am working on Windows 7 64-bit.
注意
2 - ; nul
重定向应避免大量错误消息 ERROR:未找到类型为* .txt的文件。
当当前处理目录中没有文件匹配给定面具( *。txt
)。
Note:
The 2> nul
redirection should avoid numerous error messages ERROR: Files of type "*.txt" not found.
when no file in the currently processed directory matches the given mask (*.txt
).
推荐答案
使用格式 0xHH
的 forfiles
的十六进制字符代码替换功能,可以自行嵌套。在这种情况下,使用 00x7840
,因此第一个(外部) forfile
循环替换 0x78
部分由 x
导致 0x40
,这又由第二个(内部) forfile
循环替换为 @
。
The trick is to use the hexadecimal character code replacement feature of forfiles
in the format 0xHH
, which can be nested on its own. In this context, 00x7840
is used, hence the first (outer) forfiles
loop replaces the 0x78
portion by x
, resulting in 0x40
, which is in turn resolved by the second (inner) forfiles
loop by replacing it with @
.
一个简单的 0x40
不 c $ c $ for C $ c>替换第一遍中的十六进制代码而然后它处理第二遍的 @
变量,因此 0x40file
将被替换先通过 @file
,然后再通过外部 forfiles
循环扩展为当前迭代的项。
A simple 0x40
does not work as forfiles
replaces hexadecimal codes in a first pass and then it handles the @
variables in a second pass, so 0x40file
will be replaced by @file
first and then expanded to the currently iterated item by the outer forfiles
loop both.
以下命令行遍历给定的根目录,并显示每个直接子目录的相对路径(由外部 forfiles
loop)和其中发现的所有文本文件(由$ forfiles
循环迭代):
The following command line walks through a given root directory and displays the relative path of each immediate sub-directory (iterated by the outer forfiles
loop) and all text files found therein (iterated by the inner forfiles
loop):
2> nul forfiles /P "C:\root" /M "*" /C "cmd /C if @isdir==TRUE forfiles /P @path /M *.txt /C 0x22cmd /C echo @relpath -- 00x7840file0x22"
输出可能看起来像(相对子目录路径剩下,文本文件正确):
The output might look like (relative sub-directory paths left, text files right):
.\data_dir -- "text_msg.txt"
.\logs_dir -- "log_book.txt"
.\logs_dir -- "log_file.txt"
代码说明
- 如上所述,
00x7840file
部分将外部<$ c $部分隐藏@file
变量名称c> forfiles 命令,并将其替换转移到内部forfiles
命令; - 以避免任何麻烦引用
和
cmd / C
,在/ C
外部forfiles
的切换可以通过说明它们的十六进制代码来避免0x22
;
(forfiles
支持转义引号,如\
,但是cmd / C
不关心\
,因此它会检测到;
0x22
对cmd
没有特殊的含义,所以它是安全的) -
如果
语句检查外部forfile
循环枚举的项目是否是一个目录,如果不是,则跳过内部forfiles
loop; - 如果枚举的子目录不包含与给定模式匹配的任何项目,
forfiles
返回错误消息,如错误:找不到类型* .txt的文件。
at STDERR;为了避免这样的消息,重定向2> nul
已被应用;
- as described above, the
00x7840file
portion hides the@file
variable name from the outerforfiles
command and transfers its replacement to the innerforfiles
command; - to avoid any trouble with quotes
"
andcmd /C
, quotes within the string after the/C
switch of the outerforfiles
are avoided by stating their hexadecimal code0x22
;
(forfiles
supports escaping quotes like\"
, howevercmd /C
does not care about the\
and so it detects the"
;0x22
has no special meaning tocmd
and so it is safe) - the
if
statement checks whether the item enumerated by the outerforfiles
loop is a directory and, if not, skips the innerforfiles
loop; - in case the enumerated sub-directory does not contain any items that match the given pattern,
forfiles
returns an error message likeERROR: Files of type "*.txt" not found.
at STDERR; to avoid such messages, redirection2> nul
has been applied;
步骤一步一步的更换:
Step-by-Step Replacement:
这是上面的命令行,但删除重定向,仅用于演示:
Here is the above command line again but with the redirection removed, just for demonstration:
forfiles /P "C:\root" /M "*" /C "cmd /C if @isdir==TRUE forfiles /P @path /M *.txt /C 0x22cmd /C echo @relpath -- 00x7840file0x22"
现在我们将提取嵌套命令行将要一个接一个执行。
We will now extract the nested command lines which are going to be executed one after another.
取上述示例输出第一行的项目( .\data_dir - text_msg.txt
),外部 forfile
命令执行的命令行是:
Taking the items of the first line of the above sample output (.\data_dir -- "text_msg.txt"
), the command line executed by the outer forfiles
command is:
cmd /C if TRUE==TRUE forfiles /P "C:\root" /M *.txt /C "cmd /C echo ".\data_dir" -- 0x40file"
所以内部 forfiles
命令行看起来像( cmd / C
被删除,而如果
条件满足):
So the inner forfiles
command line looks like (cmd /C
removed, and the if
condition is fulfilled):
forfiles /P "C:\root" /M *.txt /C "cmd /C echo ".\data_dir" -- 0x40file"
现在执行的命令行内部 forfiles
命令是(注意在 .\data_dir
之间删除的文字引用,并立即更换 0x40file
通过变量值 @file
):
Now the command line executed by the inner forfiles
command is (notice the removed literal quotes around .\data_dir
and the instant replacement of 0x40file
by the value of variable @file
):
cmd /C echo .\data_dir -- "text_msg.txt"
通过这些步骤,从最内层到最外层的命令行,您可以嵌套两个以上的 forfile
循环。
Walking though these steps from the innermost to the outermost command line like that, you could nest even more than two forfiles
loops.
注意:
所有路径或文件名相关的 @
- 变量被每个引用的字符串替换;然而,上面显示的示例输出不包含目录路径的任何周围的引号;这是因为 forfile
从 > / C 切换;在这里输出它们,将
@relpath
在命令行中替换为 00x7822 @ relpath00x7822
; \\\@ relpath\\\\
也可以(但不建议不要混淆 cmd
)。
All path- or file-name-related @
-variables are replaced by quoted strings each; however, the above shown sample output does not contain any surrounding quotes for the directory paths; this is because forfiles
removes any literal (non-escaped) quotes "
from the string after the /C
switch; to get them back in the output here, replace @relpath
in the command line by 00x7822@relpath00x7822
; \\\"@relpath\\\"
works too (but is not recommended though to not confuse cmd
).
由于 forfiles
不是一个内部命令,所以应该可以嵌套它,而没有 cmd / C
前缀,例如 forfiles / Cforfiles / M *
,例如(除非使用任何额外的内部或外部命令,命令级联,重定向或管道,其中 cmd / C
是强制性的)。
但是,由于在 / C之后错误地处理命令行参数, code>切换
forfiles
,您实际上需要将其说明为 forfiles / Cforfiles f orfiles / M *
,所以内部 forfiles
命令翻倍。否则会抛出一条错误消息( ERROR:无效的参数/选项
)。
这篇文章中已经找到了最好的解决方法:无cmd / c的forfile文件(滚动到底部)。
Since forfiles
is not an internal command, it should be possible to nest it without the cmd /C
prefix, like forfiles /C "forfiles /M *"
, for instance (unless any additional internal or external command, command concatenation, redirection or piping is used, where cmd /C
is mandatory).
However, due to erroneous handling of command line arguments after the /C
switch of forfiles
, you actually need to state it like forfiles /C "forfiles forfiles /M *"
, so the inner forfiles
command doubled. Otherwise an error message (ERROR: Invalid argument/option
) is thrown.
This best work-around has been found at this post: forfiles without cmd /c (scroll to the bottom).
这篇关于如何正确地嵌套两个`forfiles`循环(以便内部体扩展两个迭代级别的变量)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!