Powershell 如何批量检测文件名中的字符串?
我正在尝试将包含数千个公司文档的一系列文件夹按字母顺序排序,并使用命名方案“姓氏,名”将单个文件夹列表排序 我试图排序的文档在文件名中有其主题的名称。例如,一个文件可以称为“Powershell 如何批量检测文件名中的字符串?,powershell,batch-file,Powershell,Batch File,我正在尝试将包含数千个公司文档的一系列文件夹按字母顺序排序,并使用命名方案“姓氏,名”将单个文件夹列表排序 我试图排序的文档在文件名中有其主题的名称。例如,一个文件可以称为“Baggins\u Frodo\u Resume”或“Snow,Jon-Resume”。我需要将这些文件分别排序到名为“Snow,John”和“Baggins,Frodo”的文件夹中 我在名为“list of names.txt”的文本文件中有每个文件夹的名称,格式如下: Last First Baggins Frodo S
Baggins\u Frodo\u Resume
”或“Snow,Jon-Resume
”。我需要将这些文件分别排序到名为“Snow,John
”和“Baggins,Frodo
”的文件夹中
我在名为“list of names.txt”的文本文件中有每个文件夹的名称,格式如下:
Last First
Baggins Frodo
Snow Jon
用简单的英语写出来,我想让批处理文件遵循下面概述的步骤。我在应该是变量的术语周围使用了括号
名称列表.txt
”中的第一行提前谢谢你的时间,我真的很感激 我可以为您提供不同的方法吗
@echo off
setlocal EnableDelayedExpansion
rem Within directory [C:\folder that needs sorting]...
cd "C:\folder that needs sorting"
rem Process the list of folder names. Note that %%a=Last and %%b=First
rem Note that "usebackq" option is needed because the file name is enclosed in quotes
for /F "usebackq tokens=1,2" %%a in ("C:\folder\of\list of names.txt") do (
rem Move all file names with the name scheme "Last*First*.*" into "Last, First" folder
move "%%a*%%b*.*" "C:\base\folder\of\%%a, %%b"
)
由于您已将其标记为
powershell
,因此我假设您对使用它的解决方案持开放态度。此代码以CSV文件的形式读取名称列表.txt
文件,然后迭代目录中的文件以查看是否存在匹配项。如果有,它会将文件移动到新目录。当您确信将创建正确的目录并适当移动文件时,从mkdir
和Move Item
命令中删除-WhatIf
$thedir = 'C:\src\t\nc\files'
$newdir = 'C:\src\t\nc\new'
$listfile = 'list of names.txt'
$thefiles = Get-ChildItem -File -Path $thedir
Import-Csv -Path (Join-Path -Path $thedir -ChildPath $listfile) -Delimiter ' ' |
ForEach-Object {
foreach ($file in $thefiles) {
if (($file.Name -match $_.Last) -and ($file.Name -match $_.First) -and ($file.Name -ne $listfile)) {
$dirname = $_.Last + ', ' + $_.first
$newpath = Join-Path -Path $newdir -ChildPath $dirname
if (-not (Test-Path -Path $newpath)) { mkdir -Path $newpath -WhatIf }
Move-Item -Path $file.fullname -Destination $newpath -WhatIf
}
}
}
@ECHO关闭
SETLOCAL ENABLEDELAYEDEXPANSION
设置“sourcedir=U:\sourcedir”
设置“destdir=U:\destdir”
设置“filename1=%sourcedir%\q56380365.txt”
设置/a maxwords=0
名称文件中每行的rem…到%%a
对于/f“usebackqdelims=“%%a IN”(“%filename1%”)DO(
快速眼动分析线
呼叫:单词%%a
如果!字数!lss 0转到:EOF
IF!wordcount!gtr!maxwords!SET/a maxwords=!wordcount!
)
::现在在maxwords中添加max#words
:斯堪的纳维亚
名称文件中每行的rem…到%%a
对于/f“usebackqdelims=“%%a IN”(“%filename1%”)DO(
这行有多少字?
呼叫:单词%%a
IF!wordcount!相等%maxwords%(
rem使用找到的第一个字作为筛选器读取整个源目录
对于/f“delims=“%%h IN('dir/b/a-d”%sourcedir%\!\1!*“2^>nul”)执行以下操作(
调用:匹配名称“%%h”
)
)
)
设置/a maxwords-=1
如果%maxwords%gtr 0转到scandir
后藤:EOF
::建立“字数”并将字数设置为#*;细分
字体文字
呼叫:清除#
SET/a字数=0
设置“allwords=%~1%~2”
设置“subdir=%~1”
设置“细分2=%~2”
::如果提供的字数超过2个,则出错
如果第%*&SET/a行出现“%~3”neq”回显错误,则wordcount=-1&GOTO:EOF
:wordloop
SET/a字数+=1
呼叫:atom%allwords%
设置“#%wordcount%=%car%”
如果定义了cdr,则设置“allwords=%cdr%”并转到wordloop
后藤:EOF
::第一个字到car,其余的字到cdr
:原子
设置“汽车=%1”
设置“cdr=”
:atomlp
移位
如果“%1”neq“设置”cdr=%cdr%%1“&转到atomlp
如果已定义cdr,则设置“cdr=%cdr:~1%”
后藤:EOF
::删除开始时的变量#
:清除#
对于%%b IN(#)DO For/F“delims=”%%a IN('set%%b 2^>Nul')DO set“%%a=”
后藤:EOF
::将%1中的文件名与#*中的%maxwords%字匹配,如果匹配则移动
:matchname
设置“文件=%~1”
设置/匹配=1
::将逗号、下划线[etc]替换为空格
设置“文件=%file:,=%”
设置“文件=%file:\=%”
:匹配循环
调用:atom%文件%
如果/i“%car%”“neq”!#%match%”转到:EOF
设置“文件=%cdr%”
如果%match%neq%maxwords%SET/a match+=1&转到matchloop
::所有匹配-移动
MD“%destdir%\%subdir%,%subdir2%”2>NUL>NUL
回显移动“%sourcedir%\%~1”%destdir%\%subdir%,%subdir2%
后藤:eof
比我想象的要复杂一些。由于使用了delayedexpansion
,因此通常会出现有关等特殊字符的警告代码>和&
以及其他非字母数字应仔细处理。正常的字母数字和逗号应该可以
这种方法首先检查我的系统上的名称文件-q56380365.txt
。它不仅允许两个名称,还允许一个带引号的字符串,因此可以使用像“van der Waals”Johannes这样的行。每一行都被传递到:words
例程,该例程为子目录结构建立子目录和子目录2
,并对单个单词进行计数,并将它们放入环境变量#1
,#2
。#n
。如果传递给:words
的字符串超过2个,则它将wordcount
返回为-1,以在报告行内容后标记错误。这样可以确保名称的两个部分被正确识别。
$thedir = 'C:\src\t\nc\files'
$newdir = 'C:\src\t\nc\new'
$listfile = 'list of names.txt'
$thefiles = Get-ChildItem -File -Path $thedir
Import-Csv -Path (Join-Path -Path $thedir -ChildPath $listfile) -Delimiter ' ' |
ForEach-Object {
foreach ($file in $thefiles) {
if (($file.Name -match $_.Last) -and ($file.Name -match $_.First) -and ($file.Name -ne $listfile)) {
$dirname = $_.Last + ', ' + $_.first
$newpath = Join-Path -Path $newdir -ChildPath $dirname
if (-not (Test-Path -Path $newpath)) { mkdir -Path $newpath -WhatIf }
Move-Item -Path $file.fullname -Destination $newpath -WhatIf
}
}
}