我实际上并没有与 Batch 或 PowerShell 有任何真正的接触点,不过,我已经建立了一个员工目录,现在正在寻找解决方案,其中文档通过脚本自动复制到上述目录中:
- 要复制的文档当前都在一个文件夹中,应复制到该目录的相应子文件夹中。
- 文档的文件名结构如下,其中
XX
/XXXX
是在分配中起作用的变量:ABCD_123456_1234567_12345_XX.pdf
ABCD_123456_1234567_12345_XXXX.pdf
- 目标目录也包含这些,目前大约有五十个不同的目录
是否可以仅指向第三个下划线和文件扩展名之间的变量,因为这些变量会有所不同,可能还需要添加三位或五位数字的变量?
- 我已经使用了搜索功能,但没有找到与给定示例完全对应的内容:
C:\ABCD_123456_1234567_12345_99
→\\11/17/19/1991\Directory\99_ABCD\
C:\ABCD_123456_1234567_12345_9999
→\\11/17/19/1991\Directory\9999_ABCD\
- 可能:
C:\ABCD_123456_1234567_12345_999
→\\11/17/19/1991\ directory\999_ABCD\
C:\ABCD_123456_1234567_12345_99999
→\\11/17/19/1991\Directory\99999_ABCD\
我曾尝试用 来进行设置$FileName-split
,但并没有成功,但我设法完成了文件名的填写,以便进行实际计数,如 30:27:
C:\ABCD_123456_1234567_12345_99
→C:\ABCD_123456_1234567_12345_0099
- 我正在努力解析目标文件夹,所有文件夹都存在并且文件名中都有变量,到目前为止:
$Directory = "C:\Folder\" $FileNames = (Get-Item $Directory).GetFiles() foreach($FileName in $FileNames) { $Destination = "\\10.10.10.10\destinationfolder" { Move-Item -Path $FileName -Destination $Destination } }
有没有办法通过匹配来移动文件,或者我是否必须通过计数来解析所有目标文件夹,以便设置要检查的部分?
这可能形象化
答案1
这是一个 PowerShell 解决方案:
$Destination = "\\10.10.10.10\destinationfolder"
Get-ChildItem "C:\Folder" | ForEach-Object {
$Head = ($_.BaseName -split '_')[0]
$Tail = ($_.BaseName -split '_')[-1]
$DestinationPath = Join-Path $Destination ("{0}_{1}" -f $Head, $Tail)
New-Item -Path $DestinationPath -ItemType Directory -ErrorAction SilentlyContinue
Copy-Item $_.FullName $DestinationPath -Force
}
更新:
根据您的评论,我猜这更符合您的要求。但是,您必须确保每个结尾都只有一个匹配的文件夹。例如,如果有一个文件夹被调用abc_123
,另一个文件夹被调用def_123
,则只会选择第一个文件夹,因为根据您的评论,我们只考虑结尾
$Destination = "\\10.10.10.10\destinationfolder"
Get-ChildItem "C:\Folder" | ForEach-Object {
$Tail = ($_.BaseName -split '_')[-1]
$Filter = "*_{0}" -f $Tail
$DestDir = Get-ChildItem $Destination -Filter $Filter -Directory | Select-Object -ExpandProperty FullName -First 1
if ($DestDir) {
Copy-Item $_.FullName $DestDir -Force
} else {
"No Directory was found that matched the Filter {0} in Directory {1}" -f $Filter, $Destination | Write-Host
}
}
它执行以下操作:
$Destination
首先在变量中设置目标文件夹- 获取文件夹中的所有项目
Get-ChildItem
(如果您需要进行递归,请添加开关-Recurse
,如果您只想要添加某些文件类型-Filter *.txt
或任何其他扩展名) - 循环遍历所有找到的文件
ForEach-Object
- 拆分基本名称(即不带扩展名的文件名)
_
并获取基本名称的最后一部分并将其保存在$Ending
变量中 - 通过将结束变量格式化为文件夹名称来计算文件夹名称
-f
- 用于
Join-Path
连接目标和计算文件夹并将其保存在$Destinationpath
- 如果文件夹不存在,请使用 创建该文件夹
New-Item
。如果文件夹已经存在,此行不会覆盖现有文件夹 - 使用以下方法将项目复制到目标文件夹
Copy-Item
答案2
我不明白你的问题,但如果你想复制并粘贴这样的文件
ABCD_123456_1234567_12345_1.txt copy into 1_ABCD
ABCD_123456_1234567_12345_2.txt copy into 2_ABCD
ABCD_123456_1234567_12345_3.txt copy into 3_ABCD
ABCD_123456_1234567_12345_9999.txt copy into 9999_ABCD
那么也许这个 cmd 命令可以帮助你
echo D|for /l %x in (1,1,20) do @xcopy ABCD_123456_1234567_12345_%x.txt ABC_%x\ /Y /Q
第二个命令具有相同的输出:
for /l %x in (1,1,20) do @xcopy ABCD_123456_1234567_12345_%x.txt ABC_%x\ /Y /Q
如果不存在,此命令将创建一个文件夹,然后粘贴文件,如果文件存在于文件夹中,它将覆盖该文件
更新:
查找不带扩展名的文件名的命令(并将结果附加到 filenamewithoutext.txt 中)
for /f %x in ('dir /b') do @echo %~nx>>filenamewithoutext.txt
读取输出文件并将变量保存到新文件中 variables.txt
for /f "tokens=5 delims=_" %x in (filenamewithoutext.txt) do @echo %x>>variables.txt
读取变量并将文件复制到不同的文件夹中
for /f %x in (variables.txt) do @xcopy ABCD_123456_1234567_12345_%x.txt ABC_%x\ /Y /Q
你可以ABC_%x
改为%x_ABC
答案3
当我阅读你的问题时,我认为这应该可行:
$Source = 'C:\Folder\'
$Destination = '\\10.10.10.10\destinationfolder\'
Get-ChildItem -Path $Source -FIlter *.pdf -File | ? { ($BaseName = $_.BaseName) -match '_' } | ForEach{
$Head = $BaseName.Split('_')[0]
$Tail = $BaseName.Split('_')[-1] ### (Index of -1) -> Last array element
$SubFolder = "$Tail`_$Head" ### *** Escaped <underscore> required ***
If ( Test-Path ( $FullPath = Join-Path $Destination $SubFolder ) ) {
Copy-Item -Literal $_.FullName $FullPath
} Else {
'"{0}" not copied because the directory "{1}" does not exist' -f $_.Name , $FullPath | Write-Output
}
}
ForEach 对象 • String.Split() 方法 • 连接路径 • 测试路径 • 复制项目
调试
我使用这段代码来排除字符串操作故障,发现了在扩展字符串中使用下划线的问题。将所有中间变量放在GridView
快速扫描:
Get-ChildItem -Path $Source -FIlter *.pdf -File | ? BaseName -match '_' | ForEach{
$Head = $_.BaseName.Split('_')[0]
$Tail = $_.BaseName.Split('_')[-1]
$SubFolder = "$Tail`_$Head"
$FullPath = Join-Path $Destination $SubFolder
[PSCustomObject]@{
'Head' = $Head
'Tail' = $Tail
'SubFolder' = $SubFolder
'FullPath' = $FullPath
'SubExists' = Test-Path $FullPath
}
} | Out-gridview
优化
中间变量在开发/测试/调试过程中非常有用,但可能会减慢执行多次的循环内的速度。因此,一旦分配看起来是可靠的,我就会反向工作,首先将表达式定义复制$SubFolder
到剪贴板,然后用括号中的定义替换$SubFolder
中的出现$FullPath = ...
,然后对该定义中的变量执行相同的操作。还将分配与第一次使用相结合。结果是:
Get-ChildItem -Path $Source -FIlter *.pdf -File | ForEach{
If ( ($BaseName = $_.BaseName) -match '_' ) {
If ( Test-Path ( $FullPath=Join-Path $Destination "$($BaseName.Split('_')[-1])`_$($BaseName.Split('_')[0])" ) ) {
Copy-Item -Literal $_.FullName $FullPath
} Else {
'"{0}" not copied because the directory "{1}" does not exist' -f $_.Name , $FullPath | Write-Output
}
}
}
阅读起来非常困难,但对于大型数据集来说还是值得的。