标题: [问题求助] PowerShell动态移动符合条件的文件夹 [打印本页]
作者: 5i365 时间: 2022-2-9 20:13 标题: PowerShell动态移动符合条件的文件夹
桌面上有一个Task文件夹, 其下有4个一级子文件夹, 名字分别是 1 2 3 4
Task下的文件夹结构图请看最后面:
结构具体描述:
1文件夹下: 有 OK A1 A2 文件夹:
A1文件夹下有文件 YES
2文件夹下: 有 OK B1 B2 文件夹:
B1文件夹下有文件 YES
3文件夹下: 有 OK NO C1 C2 文件夹
4文件夹下: 有 OK NO D1 D2 文件夹
-------------------------------------------------------------------------------
逻辑描述①
Task下的一级子文件夹中, 如果只包含OK文件夹, 不包含NO文件夹, 例如 文件夹 1 和 2 , 则检查除OK外的其它文件夹:
如果有YES文件: 例如 1下的A1, 2下的B1, 符合条件, 则文件夹 A1 和 B1 就是要移动的对象,
逻辑描述②
Task下的一级子文件夹中, 如果既包含OK文件夹, 又包含NO文件夹, 则这个一级子文件夹是目标文件夹, 例如 文件夹 3 和 4 , 其下的文件夹数量小于5时, 就满足了条件 【脚本中文件夹数量阙值变量定义为 $QZ=5】
-----------------------------------------------------------------------------------------
Ps脚本执行后:
就会将文件夹 A1 移动到 文件夹 3 下, 然后将文件夹下的YES文件命名为其原来的父父文件夹名 即1, 此时 3 下的文件夹数量 =5 不小于5了,不满足条件了, 也就不能再移过来文件夹了,
此时文件夹 4 还满足条件, 所以B1就移动到了 4 下, 然后将文件夹下的YES文件命名为其原来的父父文件夹名 即2
实际情况中, 一级文件夹会有多个, 一级文件夹下的子文件夹也会有多个, 但是规律就是上面这样, 每次执行脚本时, 符合条件的文件夹会动态的移动, 感觉实在太复杂了, 不知从哪里搞起, 请求高手支招, 非常感谢!!!
示例文件夹: https://send.cm/d/8gO0
--------------------------------------------------------------------------------------------------------------------------
C:\Users\Administrator\Desktop>tree task /f
卷 Win 的文件夹 PATH 列表
卷序列号为 448B-18AC
C:\USERS\ADMINISTRATOR\DESKTOP\TASK
├─1
│ ├─A1
│ │ A1.txt
│ │ YES
│ │
│ ├─A2
│ │ A2.txt
│ │
│ └─OK
├─2
│ ├─B1
│ │ B1.txt
│ │ YES
│ │
│ ├─B2
│ │ B2.txt
│ │
│ └─OK
├─3
│ ├─C1
│ │ C1.txt
│ │
│ ├─C2
│ │ C2.txt
│ │
│ ├─NO
│ └─OK
└─4
├─D1
│ D1.txt
│
├─D2
│ D2.txt
│
├─NO
└─OK
作者: for_flr 时间: 2022-2-10 16:43
- $num=5
- [System.Collections.ArrayList]$src=@()
- $dir=dir -filter *.|?{(dir $_ -name) -contains "OK" -and (dir $_ -name) -notcontains "NO"}
- $src+=$dir|%{dir $_ -exclude OK|?{(dir $_ -n) -contains "YES"}}
- $des+=dir -filter *.|?{(dir $_ -name) -contains "OK" -and (dir $_ -name) -contains "NO"}
- $des|%{for($i=(dir $_).count;$i -lt $num;$i++){move $src[0] $_;$src.removeat(0)}}
复制代码
作者: 5i365 时间: 2022-2-11 06:47
本帖最后由 5i365 于 2022-2-11 07:48 编辑
回复 2# for_flr
感谢帮忙, 我把下面的代码存成BAT文件然后和要处理的Task文件夹放在一个文件夹下, 执行后转移文件夹成功, 但是没有将YES文件命名为其原来的父父文件夹名
【PS:上面的示意图加了/F 参数显示文件了, 逻辑描述文字也更清楚了】- #@&cls&powershell "type '%~0'|out-string|iex"&pause&exit
-
- cd Task
-
- $num = 5
-
- [System.Collections.ArrayList]$src = @()
-
- $dir = dir -filter *. | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -notcontains "NO"
- }
-
- $src += $dir | foreach{
- dir $_ -exclude OK |
- where{ (dir $_ -n) -contains "YES" }
- }
-
- $des += dir -filter *. | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -contains "NO"
- }
-
- $des | foreach{
- for ($i = (dir $_).count; $i -lt $num; $i++)
- {
- move $src[0] $_
- $src.removeat(0)
- }
- }
复制代码
作者: 5i365 时间: 2022-2-11 06:56
本帖最后由 5i365 于 2022-2-11 07:48 编辑
回复 2# for_flr
另外, 如果我把 2 下的 B1 删除, 然后执行脚本后, A1 能转移成功, 但是报下面的错误
【PS:上面的示意图加了/F 参数显示文件了, 逻辑描述文字也更清楚了】
-----------------------------------------------------------------------
Move-Item : Cannot bind argument to parameter 'Path' because it is null.
At line:25 char:8
+ move $src[0] $_
+ ~~~~~~~
+ CategoryInfo : InvalidData: ( [Move-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.MoveItemCom
mand
Exception calling "RemoveAt" with "1" argument(s): "Index was out of range. Must be non-negative and less than the size
of the collection.
Parameter name: index"
At line:26 char:3
+ $src.removeat(0)
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
请按任意键继续. . .
作者: for_flr 时间: 2022-2-11 10:50
- #@&cls&powershell "type '%~0'|out-string|iex"&pause&exit
- cd Task
- $num = 5
- [System.Collections.ArrayList]$src = @()
- $dir = dir -filter *. | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -notcontains "NO"
- }
- $src += $dir | foreach{
- dir $_ -exclude OK |
- where{ (dir $_ -n) -contains "YES" }
- }
- $des += dir -filter *. | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -contains "NO"
- }
- $src|foreach{
- if(test-path $_\yes){
- ren $_\yes $_.parent.name
- }
- }
- $des | foreach{
- for ($i = (dir $_).count; $i -lt $num; $i++){
- if($src.count -gt 0){
- move $src[0] $_
- $src.removeat(0)
- }
- }
- }
复制代码
sorry,没注意到重命名的要求,错误提示是因为可移动对象数量和目标空位数量不对等。现在加了个if判断。(原代码是准备放到task目录下。)
作者: 5i365 时间: 2022-2-11 11:22
回复 5# for_flr
技术碉堡了, 真没想到这么复杂的逻辑, 大侠居然搞定了, 目前还没有实际使用, 一直在手动操作, 想多测试之后再用,
现在我想再在加个逻辑, 请教大侠, 下面的描述中, 大字号是新加的逻辑, 正常字号还是原来的描述, 其它的逻辑也没有变化
1文件夹下: 有 OK A1 A2 A3文件夹,
A1文件夹下有文件 YES 没有DD
A3文件夹下有文件 DD 没有YES
2文件夹下: 有 OK B1 B2 B3文件夹,
B1文件夹下有文件 YES 没有DD
B3文件夹下有文件 DD 没有YES
描述①
Task下的一级子文件夹中, 如果只包含OK文件夹, 不包含NO文件夹, 例如 文件夹 1 和 2 , 则检查除OK外的其它文件夹:
A. 如果有YES文件, 没有DD文件: 例如 1下的A1, 2下的B1, 符合条件, 则文件夹 A1 和 B1 就是要移动的对象
B. 如果没有YES文件, 有DD文件: 例如 1下的A3, 2下的B3, 符合条件, 则将文件夹 A3 和 B3 移动到 其父目录的 OK 文件夹下, 然后再删除DD文件
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
示例文件链接: https://send.cm/d/8iyx
新文件结构示意图如下:
C:\Users\Administrator\Desktop>tree task2 /f
卷 Win 的文件夹 PATH 列表
卷序列号为 448B-18AC
C:\USERS\ADMINISTRATOR\DESKTOP\TASK2
├─1
│ ├─A1
│ │ A1.txt
│ │ YES
│ │
│ ├─A2
│ │ A2.txt
│ │
│ ├─A3
│ │ A3.txt
│ │ DD
│ │
│ └─OK
├─2
│ ├─B1
│ │ B1.txt
│ │ YES
│ │
│ ├─B2
│ │ B2.txt
│ │
│ ├─B3
│ │ B3.txt
│ │ DD
│ │
│ └─OK
├─3
│ ├─C1
│ │ C1.txt
│ │
│ ├─C2
│ │ C2.txt
│ │
│ ├─NO
│ └─OK
└─4
├─D1
│ D1.txt
│
├─D2
│ D2.txt
│
├─NO
└─OK
作者: 5i365 时间: 2022-2-11 11:26
想知道, 这么复杂的逻辑, 用BAT能实现吗?
作者: qixiaobin0715 时间: 2022-2-11 12:13
我觉得bat应当也能实现,关键时要理清头绪。
作者: for_flr 时间: 2022-2-11 13:02
- #@&cls&powershell "type '%~0'|out-string|iex"&pause&exit
- cd Task
- $num = 5
- [System.Collections.ArrayList]$src = @()
- $dir = dir -filter *. | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -notcontains "NO"
- }
- $src += $dir | foreach{
- dir $_ -exclude OK |
- where{ (dir $_ -n) -contains "YES" -and (dir $_ -n) -notcontains "DD" }
- }
- $dir|foreach{
- cd $_
- dir -exclude OK |foreach{
- if((dir $_ -n) -contains "DD" -and (dir $_ -n) -notcontains "YES"){
- del $_\DD
- move $_ OK
- }
- }
- cd ..
- }
- $des += dir -filter *. | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -contains "NO"
- }
- $src|foreach{
- if(test-path $_\yes){
- ren $_\yes $_.parent.name
- }
- }
- $des | foreach{
- for ($i = (dir $_).count; $i -lt $num; $i++){
- if($src.count -gt 0){
- move $src[0] $_
- $src.removeat(0)
- }
- }
- }
复制代码
就是多几个if条件,不算复杂。
批处理的话
用if exist 轻松实现。
作者: 5i365 时间: 2022-2-11 14:21
本帖最后由 5i365 于 2022-2-11 14:32 编辑
回复 9# for_flr
大侠,太牛X了, 目前有两个疑问:
1. 代码中用了 -notcontains "NO" 那如果文件夹的名字是 NO2 或 1NO 还稳吗?
2. 我在 3 和 4 文件夹下的一些子文件夹中, 也要加 DD 文件, 例如:
文件夹3 中增加了 C3文件夹 里面 也没有YES文件, 但有 DD文件
文件夹4 中增加了 D3文件夹 里面 也没有YES文件, 但有 DD文件
如何实现刚刚上面的功能? 即: C3移到 3下的OK文件夹, 然后删除DD, 同样 D3 移到 4下的OK文件夹, 然后删除DD, 其它的功能不能受影响, 最开始的逻辑有一点改变, 就是移动到OK文件夹的条件, 不再考虑 其父目录下, 是不是有 OK 和 NO 文件夹
这些逻辑如果人来理解并手动操作很简单, 但是用文字和代码描述的时候, 真是太吃力了
------------------------------------------------------------------------------------
示例文件下载链接: https://send.cm/d/8jAI
现在的文件结构如下:
C:\Users\Administrator\Desktop\T>tree Task3 /f
卷 Win 的文件夹 PATH 列表
卷序列号为 448B-18AC
C:\USERS\ADMINISTRATOR\DESKTOP\T\TASK3
├─1
│ ├─A1
│ │ A1.txt
│ │ YES
│ │
│ ├─A2
│ │ A2.txt
│ │
│ ├─A3
│ │ A3.txt
│ │ DD
│ │
│ └─OK
├─2
│ ├─B1
│ │ B1.txt
│ │ YES
│ │
│ ├─B2
│ │ B2.txt
│ │
│ ├─B3
│ │ B3.txt
│ │ DD
│ │
│ └─OK
├─3
│ ├─C1
│ │ C1.txt
│ │
│ ├─C2
│ │ C2.txt
│ │
│ ├─C3
│ │ C3.txt
│ │ DD
│ │
│ ├─NO
│ └─OK
└─4
├─D1
│ D1.txt
│
├─D2
│ D2.txt
│
├─D3
│ D3.txt
│ DD
│
├─NO
└─OK
C:\Users\Administrator\Desktop\T>
作者: 5i365 时间: 2022-2-11 14:27
本帖最后由 5i365 于 2022-2-11 14:31 编辑
回复 9# for_flr
简尔言之两句话, 现在就是两条线:
一条线, 根据 DD 文件 向其所在文件夹的父目录下的OK文件夹中移动文件夹
另一条线, 根据 YES 文件 向包含 OK和NO 文件夹的目录下移动文件夹
作者: 5i365 时间: 2022-2-11 17:08
回复 9# for_flr
关于第一个问题, 我试了
1. 代码中用了 -notcontains "NO" 那如果文件夹的名字是 NO2 或 1NO 还稳吗?
很稳! 下面的代码, 只匹配 NO
dir -dir -name | where{ $_ -contains "NO" }
作者: for_flr 时间: 2022-2-11 18:04
本帖最后由 for_flr 于 2022-2-14 09:33 编辑
回复 12# 5i365
9楼第12行,$dir改做dir就可以了。
PowerShell语法跟白话文挺像的,你可以试着自己修改的。
回复 19# 5i365
改的好,当时写的先改名后移动,犯了错;
dir -dir可以,为了获取子文件夹;
[System.Collections.ArrayList]$src = @()是为了将数组转为可以删除数组元素的arraylist。
作者: 5i365 时间: 2022-2-11 20:14
回复 13# for_flr
大侠真是太拽了, 还真是, 把$去掉就可以了!
分析单个功能的代码, 在下能大致看懂, 但是真要搞多个逻辑的事情, 就一点头绪没有, 不知道用什么, 只会改点单一功能的PS代码
再请教大侠问题, 下面的代码: dir -filter *. 应该可以换成 dir -dir 吧 百度搜索您的代码, 没找到结果, 所以就问一下
$dir = dir -filter *. | where{
(dir $_ -name) -contains "OK" -and (dir $_ -name) -notcontains "NO"
}
作者: 5i365 时间: 2022-2-11 20:48
本帖最后由 5i365 于 2022-2-11 20:50 编辑
回复 13# for_flr
大侠发现个问题,
文件夹 3 和 4 里面的子文件夹数量都是5时, 如果我在A2里面, 我放了一个YES文件, 执行PS后,
此时因为 目标文件夹 3和4的数量,均不满足移动A2的条件, 所以A2不做任何操作, 但是我发现 A2里面的 YES 文件, 改名为了 1 应该是移过去之后, 再改名
作者: 5i365 时间: 2022-2-13 09:19
本帖最后由 5i365 于 2022-2-13 09:31 编辑
回复 13# for_flr
我把根据文件DD移动到OK文件夹的功能去掉了, 只留下了最开始,那个复杂的, 根据文件夹数量移动文件夹的功能,
问题就是, 在不满足移动条件下, 仍会把源文件夹中的yes改名, 应该是先移过去, 然后再改名, 但文件名又是原来的文件夹的父目录名
感觉问题应该出在红色字的地方, 尝试加在后面蓝字的地方也不行, 不知道怎样改粉色地方的代码
#@&cls&powershell "type '%~0'|out-string|iex"&pause&exit
cd Task3
$num = 5
[System.Collections.ArrayList]$src = @()
$dir = dir -filter *. | where{
(dir $_ -name) -contains "OK" -and (dir $_ -name) -notcontains "NO"
}
$src += $dir | foreach{
dir $_ -exclude OK |
where{ (dir $_ -n) -contains "YES" }
}
$des += dir -filter *. | where{
(dir $_ -name) -contains "OK" -and (dir $_ -name) -contains "NO"
}
$src | foreach{
if (test-path $_\YES)
{
ren $_\YES $_.parent.name
}
}
$des | foreach{
for ($i = (dir $_).count; $i -lt $num; $i++)
{
if ($src.count -gt 0)
{
move $src[0] $_
#ren $_\YES $_.parent.name
$src.removeat(0)
}
}
}
作者: 5i365 时间: 2022-2-13 11:02
本帖最后由 5i365 于 2022-2-13 11:09 编辑
回复 2# for_flr
这个第5行前面是不是应该新建个数组? 这个不太理解, 我看前面 源 是先建了一个数组 [System.Collections.ArrayList]$src = @()
另外, 为什么 要$des+=直接$des=不行吗?
$des = @()
$des+=dir -filter *.|?{(dir $_ -name) -contains "OK" -and (dir $_ -name) -contains "NO"}
作者: 5i365 时间: 2022-2-13 20:20
回复 5# for_flr
终于搞定了, 删除上面红字的代码, 然后将最后的代码改为如下, 就可以了!- $des | foreach{
- for ($i = (dir $_).count; $i -lt $num; $i++)
- {
- if ($src.count -gt 0)
- {
- move $src[0] $_
- $s = $src[0].name
- $s2 = $src[0].parent.name
- ren $_\$s\YES -newname $s2
- $src.removeat(0)
- }
- }
- }
复制代码
作者: 5i365 时间: 2022-2-13 20:24
本帖最后由 5i365 于 2022-2-13 20:32 编辑
最终代码:- cd Task3; $num = 6; [Collections.ArrayList]$src = @()
-
- $dir = gci -dir | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -notcontains "NO"
- }
-
- $src += $dir | foreach{
- dir $_ -exclude OK |
- where{ (dir $_ -name) -contains "YES" }
- }
-
- $des = gci -dir | where{
- (dir $_ -name) -contains "OK" -and (dir $_ -name) -contains "NO"
- }
-
- $des | foreach{
- for ($i = (dir $_ -dir).count; $i -lt $num; $i++)
- {
- if ($src.count -gt 0)
- {
- move $src[0] $_
- $s = $src[0].name
- $s2 = $src[0].parent.name
- ren $_\$s\YES -newname $s2
- $src.removeat(0)
- }
- }
- }
复制代码
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |