首页 Powershell整理文件夹
文章
取消

Powershell整理文件夹

背景

最近被baidu盘提示说空间不足,想找一找哪些数据是不要的删除一下。

但是baidu盘并没有提供特别快特别好用的全文搜索。所以我的想法是类似CMD一样,把baidu盘上的信息离线下来,然后慢慢分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
PS C:\> tree                                     
C:.
├───Intel
   ├───Logs
   └───Wireless
       └───Data
├───PerfLogs
├───Program Files
   ├───7-Zip
      └───Lang
   ├───ACD Systems
      └───ACDSee Ultimate
          └───10.0
              ├───1033
              ├───ACDSeeSR Themes
                 ├───Black
                 ├───blackshadow
                 ├───green
                 ├───grey
                 ├───transparent
                 ├───whiteshadow
                 └───wood
              ├───AlbumGenerator
                 └───Styles
                     ├───Style1
                        ├───css

BaiduPCS

BaiduPCS是用GO语言写的,作者大哥的项目在这里 戳这里 这是一个仿linux的cli工具,有了它,列目录这个事情才算有了最基础的平台。

需求

BaiduPCS也有tree命令,但是输出效果也是和cmd的tree一样,我需要的实际效果大概和下面类似

1
2
3
4
5
6
7
 !3DS电影/ 3DS  / 3D  /   / 日本风景名胜_400x240_1400kbps_30.303fps_2pass.moflex
 !3DS电影/ 3DS  / 3D  /   / 宇宙的奥秘_400x240_1400kbps_23.976fps_2pass.moflex
 !3DS电影/ 3DS  / 3D  /   / 拯救地球_400x240_1400kbps_29.964fps_2pass.moflex
 !3DS电影/ 3DS  / 3D  /   /   1 & 2/   2_400x240_1400kbps_23.976fps_2pass.moflex
 !3DS电影/ 3DS  / 3D  /   /   1 & 2/  _400x240_1400kbps_23.976fps_2pass.moflex
 !3DS电影/ 3DS  / 3D  /   /   3 & 4/   3_400x240_1400kbps_23.976fps_2pass.moflex
 !3DS电影/ 3DS  / 3D  /   /   3 & 4/   4_400x240_1400kbps_24.000fps_2pass.moflex

这样找到文件之后,我可以按照目录去baidu盘上删东西。

实现

实现代码如下

1
2
3
4
5
6
#针对这个目标,主要是处理3种字符
#├出现这个符号,则表示这一行有一个文件名,
#如果这一行末位是/,则它是一个目录。否则,就是一个文件名
#└出现这个符号,表示下一行,会换目录,比如当前是在一个3级目录,下次可能就是2级或者1级
#│出现这个符号,表示这一行的数据处于某一个子目录下,出现一次就是1级目录
#由于要将逻辑放在函数中,所以这里用到了全局变量。
1
2
3
4
5
#为了输出更快,这里将数据放在ArrayList中,最后一次性输出。
$aa = Get-Content C:\333.txt
$aa = $aa.replace("──", "")#把正文中的横杠全删除掉,但是如果文件名中正好有这个字符,就同样会被处理掉
$arrayx = New-Object System.Collections.ArrayList
$global:pathname = ""

函数主逻辑

下面是关键部分,因为逻辑比较繁琐,写了注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

function sw ($x) {
    $x1 = $x[0] #检测每一行的第一个字符
    #根目录逻辑,如果以├开头,且以/结尾,则表示它是一个根目录。这里全局变量就设置成├以后的部分
    #。例如├── !3DS电影/
    if ($x1 -eq '├' -and $x.EndsWith('/')) {
        $global:pathname = $x.Split('├')[-1]
    }

    #子目录逻辑,如果包含│,且以/结尾,则表示它是一个子目录。这里全局变量需要累加
    #累加原值+“├”以后的部分
    #例如│   │   ├── 3D 电 影/
    if ($x1 -eq '│' -and $x.EndsWith('/') ) {
        $global:pathname = $pathname + $x.Split('├')[-1]
    }
    #子目录中的文件逻辑,如果包含│,且不以/结尾,则表示它是一个子目录的文件
    if ($x1 -eq '│' -and ($x.EndsWith('/') -eq $false)) {
        #首先生成文件名,文件名的格式为全局变量的路径名称+“├或└”右侧的信息
        $global:fname = $global:pathname + $x.Split('├')[-1].Split('└')[-1]
        #然后把数据吐到arraylist中,留到最后统一输出
        $arrayx.add($global:fname) | out-null
        if ($x -match "└") {
            #如果路径中包含└,则需要进行处理,方便下一个待处理数据进行处理。例如如下两条是生成的记录
            #
            #测试数据:
            #│   │   │   │   └── 无 敌 破 坏 王.2012_400x240_2000kbps_23.976fps_2pass.moflex
            #│   │   │   ├── 纪 录 片/
            #│   │   │   │   ├── 风光/
            #│   │   │   │   │   ├── 北碧_400x240_1400kbps_25.000fps_2pass.moflex
            #
            #以下是生成的数据:
            #!3DS电影/ 3DS 电 影/ 3D 电 影/ 电 影 v4/ 无 敌 破 坏 王.2012_400x240_2000kbps_23.976fps_2pass.moflex
            #!3DS电影/ 3DS 电 影/ 3D 电 影/ 纪 录 片/ 风光/ 北碧_400x240_1400kbps_25.000fps_2pass.moflex
            #
            #全局变量以/进行拆解,取0到 $x(未处理数据以│隔开)-3的位置,然后用/拼接回去,再加上/
            #以上面举例,无敌破坏王是$x,当前全局变量是“!3DS电影/ 3DS 电 影/ 3D 电 影/ 电 影 v4/”
            #$x可以被拆分为5个部分,他在一个4级目录下
            #全局变量以/拆解,可以被拆解为5个部分
            #所以全局变量被拆解重新组合后,变成了0..(5-3),也就是到了上一级目录。
            #而这种计算是自动的,所以可以做到从4级目录返回到3级,也可以从3级返回到1级。这里-3是上一级,-2是同级
            #至于返回之后,下一条数据如果是目录,则依然可以返回
            $global:pathname = ($global:pathname.Split('/')[0..(($x.split('│').count - 3) )] -join '/') + '/'
        }
        else {
            $global:pathname = ($global:pathname.Split('/')[0..($x.split('│').count - 2)] -join '/') + '/'
        }
    }
}

$aa | ForEach-Object { sw $_ }
$arrayx | Out-File c:\444.txt

问题

这里还有一个问题,就是如果是根目录,但是又是文件,应该如何处理。

本文由作者按照 CC BY 4.0 进行授权

Powershell 文件名包含[]时,改后缀的方法

解决scvmm与sofs配置共享权限failed to set security info