Не удается найти путь _, так как он не существует
Я пытаюсь создать небольшой скрипт в powershell, который будет перемещать файлы и каталоги для правильной локализации. Я сделал следующую команду:
Get-ChildItem -Path '.\list\' | ForEach-Object { if ($($_.Name) -like '*[1]*') {
$file = $($_.Name)
$path = $($_.FullName)
echo "$file ==> $path"
Move-Item -Path $path -Destination .\[1]\}}
и он обнаруживает правильные файлы и каталоги, но не перемещает их.
Затем я решил немного изменить команду и вместо этого создать жесткие ссылки:
Get-ChildItem -Path '.\list\' | ForEach-Object { if ($($_.Name) -like '*[1]*') {
$file = $($_.Name)
$path = $($_.FullName)
echo "$file ==> $path"
New-Item -Path ".\``[1``]\" -Name $file -Type HardLink -Target "$path"}}
и я получил следующий ответ (только 1 петля):
[1] dir1 ==> D:\test_move\list\[1] dir1
New-Item:
Line |
5 | New-Item -Path ".\``[1``]\" -Name $file -Type HardLink -Target "$path …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'D:\test_move\list\[1] dir1' because it does not exist.
Одна и та же ошибка появляется как с правами администратора, так и без них.
Что мне нужно сделать, чтобы заставить его работать?
1 ответ
Попробуйте следующее:
Get-ChildItem -LiteralPath .\list -File -Filter '*[1]*' | ForEach-Object {
$file = $_.Name
$path = $_.FullName
"$file ==> $path" # implicit `echo` aka `Write-Output`
New-Item -Force -Type HardLink `
-Path (Join-Path .\[1] $file) `
-Target ([WildcardPattern]::Escape($path)) ` # !! see PowerShell Core comments below
-WhatIf
}
Примечание. Общий параметр в приведенной выше команде служит для предварительного просмотра операции. Удалять
-WhatIf
как только вы убедитесь, что операция будет делать то, что вы хотите.
-Filter '*[1]*'
предварительно фильтруетGet-ChildItem
вывод включать только файлы, имя которых содержит подстроку дословно , потому что-Filter
Параметр использует родной для файловой системы язык подстановочных знаков, который не обрабатывает и как метасимволы.- Напротив, с более мощными шаблонами подстановочных знаков PowerShell ,
'*[1]*'
будет соответствовать любому имени, содержащему только1
, поскольку[...]
интерпретируется как набор символов или диапазон. С-like
, оператор оператора сопоставления с подстановочными знаками , вам придется использовать'*`[1`]*'
(экранирование метасимволов для дословной интерпретации с помощью`
) найти дословно[1]
подстроки.
- Напротив, с более мощными шаблонами подстановочных знаков PowerShell ,
-File
ограничивает соответствие элементов файлам , потому что жесткие ссылки поддерживаются только для файлов, а не для каталогов.-Path (Join-Path .\[1] $file)
использовать только аргумент, а не аргумент только пути к каталогу в сочетании с аргументом только имени файла, что гарантирует, что аргумент обрабатывается как буквальный (дословный) путь без интерпретации метасимволов подстановки, таких как и .- К сожалению, в сочетании с
-Name
приводит к тому, что аргумент интерпретируется как шаблон с подстановочными знаками .
- К сожалению, в сочетании с
создает целевой каталог по запросу, если это необходимо, но обратите внимание, что он также заменит любой ранее существовавший целевой файл.
Только Windows PowerShell :
([WildcardPattern]::Escape($path))
экранирует целевой путь, чтобы обработать его дословно , когда он интерпретируется как подстановочный знак , который, к сожалению, интерпретируется как аргумент. Невыполнение этого экранирования вызвало ошибку, которую вы видели.Предостережение :
В PowerShell [Core] 7+ в предложении GitHub № 13136было одобрено критическое изменение , чтобы — более разумно — рассматривать аргумент как буквальный (дословный) путь, и в этом случае вы просто использовали бы
-Target $path
.Однако в PowerShell 7.1 это изменение еще не реализовано и, к сожалению, нацелено на путь, содержащий
[
а также]
в настоящее время полностью сломан — см. GitHub issue #14534.
Обратите внимание, что многие, но не все командлеты для обработки файлов предлагают
-LiteralPath
параметр для явной передачи путей, которые должны быть восприняты буквально (дословно), в то время как
-Path
параметр — обычно подразумеваемый параметр для первого позиционного аргумента — предназначен для приема шаблонов подстановочных знаков.
Таким образом, вы могли бы сделать свой оригинальный подход сработайте следующим образом:
# Ensure that the target dir. exists.
# No escaping needed for -Path when not combined with -Name.
$null = New-Item -Type Directory -Path .\[1] -Force
# Move the file, targeted with -LiteralPath, there.
# No escaping needed for -Destination.
Move-Item -LiteralPath $path -Destination .\[1]\
Примечание. В отличие от ,
-Force
не создает целевой каталог по запросу. С другой стороны,
Move-Item
х
-Destination
более разумно интерпретирует свой аргумент буквально (дословно), в отличие от
New-Item
х
-Target
параметр.