Folder Prey has
"Deer.txt",
"Antelope.txt",
"Rabbit.txt"
Folder Predator has
"Shark.txt",
"Bear.txt",
"Cougar.txt"
Folder Habitat has
"Forest.txt",
"Ocean.txt",
"Desert.txt"
如何使用 .bat 文件生成所有 27 种可能的组合?棘手的部分是文件夹的数量不是静态的。有人可能会在以后添加文件夹 Food,或删除文件夹 Habitat。可以编写 .bat 文件来处理这个问题吗?
输出结果为:
Deer_Shark_Forest
Deer_Shark_Ocean
Deer_Shark_Desert
Deer_Bear_Forest
Deer_Bear_Ocean
Deer_Bear_Desert
Deer_Cougar_Forest
Deer_Cougar_Ocean
Deer_Cougar_Desert
Antelope_Shark_Forest
Antelope_Shark_Ocean
Antelope_Shark_Desert
Antelope_Bear_Forest
Antelope_Bear_Ocean
Antelope_Bear_Desert
Antelope_Cougar_Forest
Antelope_Cougar_Ocean
Antelope_Cougar_Desert
Rabbit_Shark_Forest
Rabbit_Shark_Ocean
Rabbit_Shark_Desert
Rabbit_Bear_Forest
Rabbit_Bear_Ocean
Rabbit_Bear_Desert
Rabbit_Cougar_Forest
Rabbit_Cougar_Ocean
Rabbit_Cougar_Desert
向你保证这不是家庭作业问题。我想将其写成批处理文件。
答案1
您可以使用以下批处理文件执行此操作:
@echo off
setlocal enabledelayedexpansion
set first_pass=yes
copy nul temp2.txt > nul
for /d %%D in (*) do (
for %%F in ("%%D"\*) do (
if !first_pass! == yes (
echo %%~nF >> temp2.txt
) else (
for /f "delims=" %%L in (temp1.txt) do (
echo %%~nF_%%L >> temp2.txt
)
)
)
set first_pass=no
del temp1.txt 2> nul
rename temp2.txt temp1.txt
)
这将创建一个名为的文件temp1.txt
。(当然,可以简单地修改脚本以使用不同的文件名和/或在屏幕上显示结果。)这是我得到的输出:
Antelope_Bear_Desert
Antelope_Bear_Forest
Antelope_Bear_Ocean
Antelope_Cougar_Desert
Antelope_Cougar_Forest
Antelope_Cougar_Ocean
Antelope_Shark_Desert
Antelope_Shark_Forest
Antelope_Shark_Ocean
Deer_Bear_Desert
Deer_Bear_Forest
Deer_Bear_Ocean
Deer_Cougar_Desert
Deer_Cougar_Forest
Deer_Cougar_Ocean
Deer_Shark_Desert
Deer_Shark_Forest
Deer_Shark_Ocean
Rabbit_Bear_Desert
Rabbit_Bear_Forest
Rabbit_Bear_Ocean
Rabbit_Cougar_Desert
Rabbit_Cougar_Forest
Rabbit_Cougar_Ocean
Rabbit_Shark_Desert
Rabbit_Shark_Forest
Rabbit_Shark_Ocean
笔记:
- 显然,这使用了
*
通配符,因此输出的顺序取决于 Windows 扩展通配符的顺序。在我的系统上,给定字母目录条目,*
将按字母顺序展开。在使用英语以外的语言的系统上,这可能会有所不同,并且/或者可以通过配置设置进行更改。为了接下来的两个要点,我将假设使用字母顺序。 - 在每个文件夹中,名称都按字母顺序排列;例如,羚羊在鹿之前,等等……,熊在美洲狮之前,等等……
- 根据您在问题中指定的期望输出,文件夹输出为撤销字母顺序;即 Prey_Predator_Habitat。
- 以上任何一种情况都可以改变(尽管不太优雅)。
setlocal enabledelayedexpansion
让我们在循环中处理变量。copy nul temp2.txt > nul
创建第二个临时工作文件。这> nul
将隐藏正常1 file(s) copied.
状态消息。for /d %%D in (*) do
循环遍历当前目录中的所有文件夹。运行批处理文件时,变量%%D
将依次取值Habitat
、Predator
和— 或当前目录中的任何文件夹。Prey
for %%F in ("%%D"\*) do
循环遍历目录中的所有文件%%D
;即我们当前从外层循环查看的目录。变量%%F
将按顺序取值,例如Habitat\Desert.txt
、Habitat\Forest.txt
和Habitat\Ocean.txt
。即使目录名称包含空格,引号也能使此操作正常工作。如果文件夹中还有其他文件,它们也会被包含。如果您只想查看
.txt
文件,请将for
语句更改为for %%F in ("%%D"\*.txt) do
。!first_pass!
就是变量first_pass
。它通常会被写成%first_pass%
,但我们需要使用这种语法,因为我们处于循环中。(这只因为我们启用了它,所以才有效,用setlocal enabledelayedexpansion
。)first_pass
是yes
在我们处理第一个目录时;即Habitat
。在这种情况下,我们只是将文件名写入文件temp2.txt
;因此,当for %%F in ("%%D"\*) do
循环完成时,temp2.txt
将包含沙漠
因为
森林
海洋%%~nF
仅评估基础文件n文件名的一部分%%F
。如果你想包含.txt
eX紧张,用%%~nxF
代替%%~nF
。for /d %%D
剧透警告:当我们第二次和第三次(等等)执行外部( )时,first_pass
是no
并且temp1.txt
是temp2.txt
来自上一次传递的。- 因此,在第二次和第三次(等等)传递时,我们执行
for /f "delims=" %%L in (temp1.txt) do
,循环遍历线在 中temp1.txt
,设置%%L
为行的内容。"delims="
是选项字符串,指定行不应被拆分成单词。这样即使文件名包含空格,此批处理文件也能正常工作。 - 例如,在外循环的第二遍(
%%D
= )中,当我们执行第二个循环的Predator
第一遍(%%F
= )时,如上所示,并且为空。Predator\Bear.txt
temp1.txt
temp2.txt
temp2.txt
- 对于来自 的每一行 (
%%L
)temp1.txt
,我们执行echo %%~nF_%%L >> temp2.txt
,将当前文件名、下划线_
和当前行 (来自temp1.txt
)写入temp2.txt
(追加)。因此,在第二个循环的第一遍 (Bear
) 之后,包括第三个循环的完整运行,temp2.txt
将包含熊_沙漠
熊_森林
熊_海洋Cougar
第二个循环的 第二遍( )将附加美洲狮沙漠
至
美洲狮森林
美洲狮海洋temp2.txt
等等。 - 当我们到达外循环的 第三遍(
%%D
= )时,是来自上一遍的,包含九行(其中六行如上所示)。然后发生与之前相同的事情(使用不同的值); 设置为,因此每一行都被复制到 前面,我们得到Prey
temp1.txt
temp2.txt
%%F
Prey\Antelope.txt
temp1.txt
temp2.txt
Antelope_
羚羊熊沙漠
羚羊熊森林
羚羊熊海洋 羚羊_美洲狮_沙漠
羚羊_美洲狮_森林
︙ - 正如预示的那样,当我们完成第二个循环并到达第一个循环的末尾时,我们将其设置
first_pass
为no
,删除当前temp1.txt
(如果有;如果尚不存在,则隐藏错误消息),并重命名temp2.txt
为temp1.txt
。
因此,我们最终得到一个长度为 27 行的文件 (Num( Habitat
) × Num( Predator
) × Num( Prey
))。您可以添加和删除文件夹和文件,因为脚本中没有任何内容是硬编码的 — 甚至文件夹的数量也没有。
- 如果有一个文件夹(例如
Job_Titles
)不包含任何文件,则不会有任何输出(因为 3 × 0 × 3 × 3 = 0)。事实上,在这种情况下,上述批处理文件会产生一堆错误消息,并且会产生一个空temp1.txt
文件(预期行为)或根本没有文件。当然,这可以修复。 - 该脚本被设计用于处理包含空格的文件或目录名称,并且已经在这种情况下进行了测试(并且似乎工作正常),但可能存在一些我没有考虑到的特殊情况。
- 不可避免的是,如果任何文件名包含
_
(下划线),输出将会产生歧义。例如,Antelope_Mountain_Lion_Forest
会产生歧义。
答案2
您可以使用 PowerShell:
$categories = gci -Directory | % {$_.Name}
Function AddCombos([int]$catPos, $root) {
gci ".\$($categories[$catPos])\*.txt" | % {
$memberTitle = [IO.Path]::GetFileNameWithoutExtension($_.Name)
If ($catPos -eq ($categories.Length - 1)) {
$root + $memberTitle
} Else {
AddCombos ($catpos + 1) ($root + $memberTitle + '_')
}
}
}
AddCombos 0 ''
首先,此脚本获取所有类别的名称(例如“Prey”)并将它们放入列表中$categories
。然后它定义一个递归函数。AddCombos
获取由 索引的类别中的所有文件$catPos
。如果它不在最后一个类别上,它将输出完成的字符串。否则,它会在将当前成员(例如“Deer”)添加到正在进行的字符串并递增$catPos
以指示应查看下一个类别后调用自身。定义该函数后,脚本从第一个类别(索引 0)开始调用它,并使用空字符串作为正在进行的工作。
请注意,类别的顺序是按字母顺序确定的。由于文件夹名称未在输出中使用,因此您可以按所需的顺序命名它们。脚本在输出中使用文本文件的标题,但如果您想通过重命名文件来控制这些顺序,您可以将该行更改$memberTitle =
为:
$memberTitle = (gc $_)[0]
这将获取每个文件内容的第一行而不是其标题。
该脚本可以处理任意数量的类别以及每个类别中的任意数量的成员。
要运行它,请将其保存为.ps1
文件,然后按照启用脚本部分中的说明进行操作PowerShell 标签 wiki。然后您可以从批处理文件运行它,如下所示:
powershell .\myscript.ps1
答案3
@echo off
setlocal enableextensions disabledelayedexpansion
for %%t in ("%temp%\%random%%random%%random%.tmp") do (
>"%%~ft" echo(*
for /d %%d in (*) do >nul 2>&1 dir /a-d "%%d" && for /f "tokens=* delims=*" %%l in ('
type "%%~ft" ^& ^>"%%~ft" break
') do for %%f in ("%%d\*") do (
>>"%%~ft" (if "%%~l"=="" (echo(%%~nf) else (echo %%l_%%~nf))
)
) & type "%%~ft" & del "%%~ft"
它将生成一个临时文件(由引用%%t
)来连接输出行。
对于每个目录 ( %%d
),都会读取、清除临时文件,并且对于%%l
临时文件中的每一行 ( ),都会再次回显,并将%%f
当前文件夹下的每个文件 ( ) 连接起来
一旦所有文件名都被连接起来,临时文件就会被发送到控制台并被删除。