Управление файлами и папками в Powershell

У меня есть папка с тысячами имен файлов.

Все имена файлов относятся к идентификатору пользователя. У некоторых пользователей в этой папке есть несколько файлов, поэтому в конце имени добавляется номер. I.E. susy.txt, susy1.txt, susy2.txt, carl.txt, carl1.txt и т. д.

Я пытаюсь создать отдельную папку для каждого пользователя с несколькими файлами и переместить все связанные файлы в эту папку. Итак, я заметил, что есть несколько подозрительных документов. Итак, я хочу создать папку с именем Susy и поместить в нее файлы susy.txt, susy1.txt и susy2.txt ... И так далее для всех файлов.

Можно ли вообще сделать это как командный файл, если да, может ли кто-нибудь указать мне правильное направление при выполнении этого? У меня немного знаний в области написания пакетных сценариев, и я хотел бы воспользоваться этим как возможностью узнать больше.

Спасибо


person Johnrad    schedule 02.10.2013    source источник


Ответы (3)


Вот более простой / компактный способ сделать это:

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

Пурист может сказать, что «лучше» использовать Test-Path перед попыткой создания каталога, но я обычно предпочитаю более компактный код; если никакие другие решения не зависят от того, существует ли каталог уже, быстрее просто пытаться создать его каждый раз и игнорировать ошибки.


Пара пояснительных примечаний в ответ на комментарий ОП:

  • ?{ } - это сокращение от Where-Object, которое фильтрует по условию, т. Е. По конвейеру передаются только объекты, соответствующие указанному условию. Таким образом, в этом случае он берет список текущего каталога и выбирает только те объекты, свойство Name которых соответствует регулярному выражению.
  • После использования оператора -match совпадения сохраняются в автоматической переменной массива $ matches. $ match [0] содержит всю совпавшую часть строки, а индексы, начинающиеся с 1, содержат группы соответствий, пронумерованные с порядкового номера левой круглой скобки, то есть $ match [1] - это группа совпадений, начинающаяся с первой обнаруженной левой круглой скобки, $ совпадение [2] - это группа совпадений, начинающаяся со второй левой скобки и т. д.

    В этом случае существует только одна группа совпадений, а $ match [1] содержит часть строки, совпадающую с (\D+), то есть последовательность последовательных нецифровых символов перед первой цифрой или точкой.

person Adi Inbar    schedule 03.10.2013
comment
Хорошо, это сработало потрясающе и именно так, как я хочу. Спасибо! Я, очевидно, не профессионал по PowerShell, однако я понимаю это по большей части ... Я просто не знаю, что означает? {} И что $ соответствует [1]. В основном [1], я не понимаю. Еще раз спасибо! - person Johnrad; 08.10.2013
comment
Еще раз спасибо! Имеет смысл! - person Johnrad; 08.10.2013

Вот мое быстрое и грязное, только что сфабрикованное решение. Он использует регулярное выражение для отделения имени пользователя от имени файла, т.е. выражение будет отделять carl от carl1.txt carl3.txt carl22.txt. Затем он уникальным образом создает папки из этих имен. Таким образом, он пытается создать carl только один раз, а не 57 раз. После этого он перемещает все carl, johnny, 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
    }
person EdgeVB    schedule 02.10.2013
comment
+1 - Обратите внимание, что это создаст каталог для пользователя, даже если у него есть только один файл, чего не просил OP. - person dugas; 03.10.2013
comment
Согласованный. Хотя, скорее всего, они хотели: P - person EdgeVB; 03.10.2013
comment
Пара проблем с этим регулярным выражением ... не основные, но мне интересно, почему вы так написали. (1) Почему . после \w в регулярном выражении? Хотя маловероятно, что имя будет состоять из одного символа, вероятно, OP не указал по крайней мере два символа. Кроме того, почему вы требуете, чтобы только первый символ, в частности, находился в классе \ w, а после этого соответствовал любому символу до первой цифры или точки? - person Adi Inbar; 03.10.2013
comment
Это был просто быстрый и грязный паттерн, основанный на начальных утверждениях OP, файлы, основанные на именах людей с числами в конце. Шаблон, безусловно, следует изменить в соответствии с их конкретными потребностями. Что касается совпадения любого символа после первого \w, это было просто ошибкой с моей стороны. Хотя, в зависимости от рассматриваемых имен файлов, это может даже сработать лучше, если, например, в именах любого из народов есть символы. Суть в том, что регулярное выражение следует изменить, чтобы оно соответствовало их точным обстоятельствам. - person EdgeVB; 03.10.2013
comment
Спасибо большое, это именно то, что мне было нужно! Изменив регулярное выражение, я получил нужные результаты. У меня есть один вопрос, и я могу показаться немного нудным. Я знаю, что $ pattern_name.match ($ _) возвращает логическое значение, которое сравнивает мое имя файла с регулярным выражением ... но что делает добавление .value? В остальном я все прекрасно понимаю. СПАСИБО! - person Johnrad; 04.10.2013
comment
Он вот так ломается. $pattern_name - это RegEx объект. У него есть метод Match, которому вы должны предоставить параметр, в данном случае переменную $_, которая является текущим именем файла, идущим по конвейеру. Как вы говорите, метод Match возвращает логическое значение, указывающее, соответствует ли имя файла регулярному выражению. Вот что интересно. Метод Match имеет несколько свойств, и одно из них - Value. Свойство Value - это фактический бит текста, удовлетворяющий совпадению. Так что в данном случае это будет sam из sam1 - person EdgeVB; 09.10.2013

Один из способов сделать это. Что это значит:

  1. Группирует файлы в каталоге по имени пользователя.

  2. Если в группе более одного файла, она создает каталог для пользователя, а затем перемещает файлы пользователя в этот каталог.

(Обратите внимание, что я добавил параметр -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 }

}
person dugas    schedule 02.10.2013