Powershell中的文件和文件夹操作

时间:2013-10-02 22:10:17

标签: file powershell file-management

我有一个包含数千个文件名的文件夹。

所有文件名都与用户的userID相关。某些用户在此文件夹中有多个文件,因此它会在名称的末尾附加一个数字。 I.E. susy.txt,susy1.txt,susy2.txt,carl.txt,carl1.txt等...

我要做的是为每个拥有多个文件的用户创建一个特定的文件夹,并将所有相关文件移动到该文件夹​​中。所以我注意到有多个可疑文件。所以我想创建一个名为Susy的文件夹,并将susy.txt,susy1.txt和susy2.txt放入其中......依此类推所有文件。

甚至可以将其作为批处理文件执行,如果是这样,有人能指出我正确的方向吗?我在编写批处理脚本方面有一些知识,并希望以此为契机,了解更多信息。

由于

3 个答案:

答案 0 :(得分:3)

这是一种更简单/更紧凑的方式:

Get-ChildItem | ?{$_.Name -match '(\D+)\d*\.txt'} | %{
  md $matches[1] -ea SilentlyContinue 
  Move-Item $_ $matches[1]
}

纯粹主义者可能会说在尝试创建目录之前对 Test-Path 进行“更好的练习”,但我通常更喜欢更紧凑的代码;如果没有其他决定取决于目录是否已经存在,那么每次尝试创建它并更快地忽略错误会更快。


一些解释性说明,以回应OP的评论:

  • ?{ } Where-Object 的简写,它过滤条件,即只有满足指定条件的对象才会传递到管道中。因此,在这种情况下,它会获取当前目录的列表,并仅选择 Name 属性与正则表达式匹配的对象。
  • 使用 -match 运算符后,匹配项存储在自动数组变量 $ matches 中。 $ matches [0] 包含字符串的整个匹配部分,以1开头的索引包含匹配组,编号从左括号的序号位置开始,即 $ matches [1] 是从遇到的第一个左括号开始的匹配组, $ matches [2] 是以第二个左括号开头的匹配组,等等。

    在这种情况下,只有一个匹配组, $ matches [1] 包含由(\D+)匹配的字符串部分,即先前连续的非数字字符的序列到第一个数字或点。

答案 1 :(得分:2)

这是我快速而又肮脏的解决方案。它使用正则表达式将用户名从文件名中分离出来,即表达式将carlcarl1.txt carl3.txt carl22.txt中分离出来。然后它唯一地从这些名称创建文件夹。所以它只尝试创建carl一次,而不是57次。之后,它会将所有carljohnny以及susy等移动到新文件夹中。

如果你是新人,不要害怕这有点令人生畏。尤其是正则表达式如果没有它们,几乎肯定有一种方法可以做到这一点,如果它们让你感到困惑,但正则表达式就是那些一旦你学会了它就会知道它在解决问题上有多棒的工具之一。

[regex]$pattern_name = '^\w.+?(?=[\d\.])'

# create folders for all the unique users
get-Childitem -File -path 'c:\scripts' | foreach-Object {$pattern_name.match($_).value } | sort -unique | foreach-Object { mkdir $_ }

# move files into those folders
get-Childitem -File -path 'c:\scripts' | foreach-Object {
    $user = $pattern_name.match($_).value 
    Move-Item -destination ".\$user" -Path $_.FullName
    }

答案 2 :(得分:0)

一种方法。这样做是:

  1. 按用户名称对目录中的文件进行分组。

  2. 如果该组有多个文件,则会为该用户创建一个目录,然后将该用户的文件移动到该目录中。

  3.   

    (注意我在所有命令中添加了-WhatIf选项   修改数据 - 您必须删除它们才能实际修改   数据。)

    # Make backup for safety
    cp -recurse .\userFiles .\userFilesBackup
    
    cd .\userFiles
    
    gci | `
    
    select-object @{n='User';e={$_.BaseName -replace "^([a-z]+)[\d]*$", '$1'}}, Name | `
    
    group-object User | `
    
    ? { $_.Count -gt 1 } | `
    
    % { `
    
    $userDirectory = $_.Name
    mkdir -WhatIf $userDirectory
    
    foreach ($f in $_.Group)
    { mv -WhatIf $f.Name $userDirectory }
    
    }