Скопируйте файл с квадратными скобками [] в имени файла и используйте * wildcard
Я использую PowerShell в Windows 7 и пишу script, чтобы скопировать кучу файлов из одной структуры папок в другую. Это похоже на компиляцию. Командлет PowerShell Copy-Item
считает, что квадратные скобки, [], являются подстановочными знаками какого-либо типа, и я почему-то не могу их избежать.
Я не могу использовать -LiteralPath
, потому что я хочу использовать подстановочный знак *, поскольку имя файла имеет дату как часть имени файла, а дата изменяется. Дата используется как номер версии.
Этот пост был полезен, но количество тиков (2x или 4x на кронштейн) не выходит за квадратные скобки.
Я не получаю ошибку; PowerShell ведет себя так же, как если бы я ввел неправильное имя файла.
Это конкретная строка, над которой я работаю:
#to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\"[RoomView] Versions explained*.pdf" -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\
И это все:
# Compiles the Fusion packet for distribution
###############################
###########Variables###########
###############################
#folder structure
$FSG = "F:\FSG"
$containerFolder = "Packet.Fusion for IT and AV Professionals"
$rootFolder = "Fusion for IT and AV pros $(Get-Date -format "MM-dd-yyyy")"
$subRoot1 = "Fusion Server"
$subRoot2 = "Scheduling Enhancement and Panels"
$subRoot2sub1 = "Scheduling Panels"
$subRoot3 = "SQL Server"
#source folders
$HW = "0.Hardware"
$3SMDoc = "0.Hardware\TPMC-3SM.Documentation"
$4SMDoc = "0.Hardware\TPMC-4SM.Documentation"
$4SMDDoc = "0.Hardware\TPMC-4SM-FD.Documentation"
$730Doc = "0.Hardware\TSW-730.Documentation"
$730OLH = "0.Hardware\TSW-730.OLH"
$CENRVS = "0.Hardware\CEN-RVS.Notes"
$ProjMgmt = "0.Project Management"
$SW = "0.Software"
$RVLicensing = "0.Software\0.RoomView.License"
$RVNotes = "0.Software\0.RoomView.Notes"
$SQLLicensing = "0.Software\database.SQL.Licensing"
$SQLNotes = "0.Software\database.SQL.Notes"
$FRVMarketing = "0.Software\Fusion RV.Marketing"
$FRVNetworking = "0.Software\Fusion RV.Networking"
$FRVNotes = "0.Software\Fusion RV.Notes"
###############################
#create the directory structure
###############################
md -Path $FSG\$containerFolder -Name $rootFolder
cd $FSG\$containerFolder\$rootFolder
md "eControl and xPanels"
md "Fusion Server" #$subRoot1
md "Getting Started as a User"
md "Project Management"
md "RoomView Connected Displays"
md "Scheduling Enhancement and Panels" #$subRoot2
md "SQL Server" #$subRoot3
cd $FSG\$containerFolder\$rootFolder\$subRoot1
md "CEN-RVS"
md "Licenseing Information"
md "Networking"
md "Official Documentation"
md "Prerequisites, including powerShell script"
md "Product Info"
md "Requirements"
md "Tech Info"
md "Windows Authentication to Fusion RV"
cd $FSG\$containerFolder\$rootFolder\$subRoot2
md "Outlook Add-in"
md "Scheduling Panels" #$subRoot2sub1
cd $FSG\$containerFolder\$rootFolder\$subRoot2\$subRoot2sub1
md "TPMC-3SM"
md "TPMC-4SM"
md "TPMC-4SM-FD"
md "TSW-730"
cd $FSG\$containerFolder\$rootFolder\$subRoot3
md "Multi-database model only"
md "SQL Licensing"
cd $FSG\$containerFolder
#reset current folder
###############################
#copy the files
###############################
#Copy-Item -Path C:\fso\20110314.log -Destination c:\fsox\mylog.log
#To the root
Copy-item -Path $FSG\$ProjMgmt\starter\"Fusion Support Group Contact info*.pdf" -Destination $FSG\$containerFolder\$rootFolder\
Copy-item -Path $FSG\$containerFolder\"Fusion for IT and AV professionals release notes.txt" -Destination $FSG\$containerFolder\$rootFolder\
#to eControl and xPanels
Copy-item -Path $FSG\$SW\xpanel.Notes\starter\*.* -Destination $FSG\$containerFolder\$rootFolder\"eControl and xPanels"\
#to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\"[RoomView] Versions explained*.pdf" -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\
Что я могу сделать, чтобы избежать квадратных скобок и по-прежнему использовать часть имени подкаталога в командлете Copy-Item
?
Ответы
Ответ 1
Существует разница между '
и '
:
- Первая - это одиночная кавычка, которая не является символом смены на клавише ".
- Вторым является обратный удар, который я думал, что использовал, но фактически не был. Это символ без смещения на клавише ~.
Это работает:
# to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\'''[RoomView''] Versions explained*.pdf' -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\
Ответ 2
В этой ситуации вы должны использовать двойные обратные кавычки с одинарными кавычками, чтобы избежать скобок. Вы также можете использовать четверные обратные метки при использовании строк в двойных кавычках.
Таким образом, фиксированная строка кода:
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\'''[RoomView''] Versions explained*.pdf' -Destination $FSG\$containerFolder\$rootFolder\'Fusion Server'\
Еще один хороший источник информации о путях к файлам, проводных символах и т.д. - прочитать эту статью: Взятие вещей (например, путей к файлам) буквально
EDIT
Спасибо @mklement0 за то, что он подчеркнул, что истинная причина этого несоответствие из-за ошибки в настоящее время в PowerShell1. Эта ошибка приводит к экранированию подстановочных знаков, а также кавычек с параметром -Path
по умолчанию вести себя иначе, чем другие параметры, например параметры -Include
и -Filter
.
To expand on @mklement0 excellent answer, and comments, and other answers below:
Чтобы лучше понять, почему нам нужны одинарные кавычки и дваобратных тика в этой ситуации; (и, чтобы выделить ошибку bug и несоответствия), давайте рассмотрим несколько примеров, чтобы продемонстрировать, что происходит:
Get-Item
и связанные с ними командлеты (Get-ChildItem
, Copy-Item
и т.д.) По-разному обрабатывают параметр -Path
, когда имеют дело с комбинацией экранированных символов , экранированных символов и ,экранированных подстановочных знаков * одновременно ***!
TLDR. Основная причина, по которой нам нужна комбинация одинарных кавычек и двойных обратных кавычек, заключается в том, что базовый поставщик PowerShell анализирует строку параметра -Path
для подстановочных знаков. Похоже, он анализируется один раз для escape-символов и второй раз для оценки подстановочного знака.
Давайте рассмотрим несколько примеров, чтобы продемонстрировать этот странный результат:
Сначала давайте создадим два файла для тестирования с именами File[1]a.txt
и File[1]b.txt
"MyFile" | Set-Content '.\File'[1']a.txt'
"MyFriend" | Set-Content '.\File'[1']b.txt'
Мы попробуем разные способы получить файл. Мы знаем, что квадратные скобки [ ]
являются подстановочными знаками wildcards, поэтому нам нужно экранировать их с помощью символа обратной галочки backtick character.
Мы попытаемся получить один файл явно.
Давайте начнем с использования одинарных кавычек буквенных строк:
PS C:\> Get-Item 'File[1]a.txt'
PS C:\> Get-Item 'File'[1']a.txt'
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
PS C:\> Get-Item 'File''[1'']a.txt'
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
Для строк в одинарных кавычках все, что требуется для извлечения файла, - это один обратный кавычек, но также работают два обратных кавычка.
Используя строки в двойных кавычках, мы получаем:
PS C:\> Get-Item "File[1]a.txt"
PS C:\> Get-Item "File'[1']a.txt"
PS C:\> Get-Item "File''[1'']a.txt"
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
Для строк в двойных кавычках, как и ожидалось, мы видим, что нам нужны два обратных знака, чтобы это работало.
Теперь мы хотим получить , оба файла, и, используют подстановочный знак.
Давайте начнем с одинарных кавычек:
PS C:\> Get-Item 'File[1]*.txt'
PS C:\> Get-Item 'File'[1']*.txt'
PS C:\> Get-Item 'File''[1'']*.txt'
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
-a---- 2019-09-06 5:49 PM 10 File[1]b.txt
В одинарных кавычках, когда у нас есть символ подстановки, нам нужно два набора обратных галочек. Один, чтобы избежать скобки, и второй обратный удар, чтобы избежать обратного удара, который мы использовали, чтобы избежать скобки, когда вычисляется подстановочный знак.
Аналогично для двойных кавычек:
PS C:\> Get-Item "File[1]*.txt"
PS C:\> Get-Item "File'[1']*.txt"
PS C:\> Get-Item "File''[1'']*.txt"
PS C:\> Get-Item "File'''[1''']*.txt"
PS C:\> Get-Item "File''''[1'''']*.txt"
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
-a---- 2019-09-06 5:49 PM 10 File[1]b.txt
С двойными кавычками немного более детально оценить с помощью подстановочного знака. В этом случае нам потребуется четыре набора обратных тиков. Для двойных кавычек нам нужны два обратных кавычка, чтобы выйти за скобки, и еще два обратных кавычки, чтобы избежать экранирующих символов, когда дело доходит до оценки звездного подстановочного знака.
EDIT
Как упоминается в @mklement0, это поведение с параметром -Path
противоречиво и ведет себя иначе, чем параметр -Include
, где для правильного выхода из скобок требуется только один обратный удар. Это может быть "исправлено" в более поздней версии PowerShell.
1 As of Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.3
Ответ 3
Способ, которым PowerShell автоматически добавляет имя файла, обычно является лучшим способом,
Пример:
copy-item '.\file`[test`].txt'
Ответ 4
В PowerShell версии 2.0 и выше escape-символ используется обратная косая черта. Например, если мы хотим удалить скобки из этой строки "[Servername: QA01]", который является видом вывода, который мы получаем из командлета Exchange PowerShell в System Center Orchestrator, мы используем следующую логику:
$string -replace '\[','' -replace '\]',''
>Servername: QA01
Это довольно странно. См., Вы должны использовать одну кавычку (которая обычно подразумевает в PowerShell "оценивать это точно как написано", поэтому это очень странный синтаксис).
Не чувствуйте себя плохо, потому что не понимаете это самостоятельно, это очень странный синтаксис.
Ответ 5
По-видимому, квадратные скобки нуждаются в двойных обратных шагах, чтобы избежать, что необычно. Ссылка здесь.
Ты уверен, что это не сработает? Я видел, как это упоминалось несколько раз.
Изменить: Да, это работает, вы использовали двойные кавычки вместо обратных ссылок.
Двойная цитата находится над символом апострофа, рядом с клавишей Enter. Backtick находится прямо под клавишей Escape, деля ключ с тильдой, ~.
Ответ 6
Я использую это:
Copy-Item $file.fullname.replace("[", "''[").replace("]", "'']") $DestDir
Ответ 7
обзор и некоторая справочная информация:
Чтобы эффективно экранировать символ, который вы хотите интерпретировать дословно как часть подстановочного выражения, он должен быть '
-escaped, как его видит целевой командлет (его базовый диск PowerShell). провайдер).
Это может быть сложно, потому что '
(backtick) также используется в качестве escape-символа в строках с двойными кавычками ("..."
) и аргументах команды без кавычек (которые по большей части ведут себя как double- строки в кавычках).
Примечание. Сценарий, о котором идет речь, не позволяет использовать -LiteralPath
, но в тех случаях, когда вы знаете, что путь является конкретным, буквальным путем, используйте -LiteralPath
(который можно закорочить на
-lp
в PowerShell Core) - лучший выбор - см. этот ответ.
При передаче аргумента параметру -Path
, поддерживающему с подстановочными знаками, командлета, связанного с поставщиком накопителя PowerShell (Get-ChildItem
, Copy-Item
, Get-Content
,...) и требуется [
и ]
следует рассматривать дословно, а не как набор символов/выражение диапазона:
Строково-буквенные представления:
'file'[1'].txt'
'
Чарс. сохраняются как есть внутри '...'
, поэтому целевой командлет видит их как положено.
"file''[1''].txt"
''
, т.е. внутри "..."
необходимо удвоение, чтобы сохранить один '
в результирующей строке (первый '
является escape-символом (двойные кавычки) внутренней строки, а второй '
является символом, которого он избегает, чтобы пройти через него.
file''[1''].txt
- То же самое для аргументов команды без кавычек, которые (по большей части) действуют как
"..."
Предупреждение: Из-за ошибки - см. эту проблему в GitHub - смешивание (без выхода) ?
или *
с экранированием [
и ]
требует, чтобы последний был дважды экранирован (с ''
, как видит целевой командлет/поставщик):
Если вы хотите сопоставить буквенное имя файла file[1].txt
с шаблоном подстановки, который буквально совпадает с [
и ]
, а также содержит специальный символ *
(для сопоставления с любым набором символов), вместо ожидаемого 'file'[1']*'
, вы Придется использовать 'file''[1'']*'
(sic); с аргументом в двойных кавычках или без экранирования вы должны эффективно использовать четырехкратные обратные запятые: "file''''[1'''']*"
/file''''[1'''']*
- см. этот ответ для получения дополнительной информации.
Обратите внимание, что прямое использование групповых символов с оператором -like
не затронуто:
'a[b' -like 'a'[*'
- это правильно - $true
,
- тогда как
'a[b' -like 'a''[*'
- по праву - жалуется на неверный шаблон.
Аналогично, параметры -Include
и -Exclude
не затрагиваются.
-Filter
воспроизводится по другим правилам для начала: [...]
как конструкция вообще не поддерживается, а символы [
и ]
. всегда считаются литералами (см. этот ответ).
Чтобы экранировать строку пути программно, через переменную используйте:
$literalName = 'file[1].txt'
$escapedName = [WildcardPattern]::Escape($literalName) # -> 'file'[1'].txt'
Ответ 8
Один из вариантов заключается в том, чтобы получить имена файлов, используя устаревший каталог, который позволит вам использовать символ подстановки *, но не пытается "покрасить" квадратные скобки. Затем загрузите этот список для перемещения элемента с помощью -literalpath
cmd /c dir *]* /b |
foreach { Move-Item -LiteralPath $_ -Destination <destination path> }
Ответ 9
Предполагая, что больше ничего не подходит, вы можете использовать? вместо скобок. Файл с именем "a [h-j]", копируемый в каталог "foo":
copy-item a?h-j? foo