Какой тип объекта в Powershell - это $<drivename>: (например, `$ code:`)?
Сегодня я использовал автозаполнение табуляции для имени переменной в Powershell 5.1 и заметил, что одним из вариантов было имя PSDrive. Название диска docs
и я хотел расширить называется $document_name
, Когда я набрал $do<tab>
оболочка действительно расширила то, что я набрал $document_name
но по какой-то причине я набрал <tab>
во второй раз, и именно тогда расширенный текст изменился на $docs:
,
Я исследовал дальше и обнаружил, что этот тип переменной существует для каждого из моих PSDrive, или, по крайней мере, расширение вкладки предполагает, что это так.
Более формально для каждого PSDrive PSD расширение вкладки считает, что $PSD:
это действительная вещь.
Мой вопрос прост: что, черт возьми, это? Вот некоторые наблюдения, которые я сделал до сих пор:
- Эти имена имеют префикс
$
, поэтому они выглядят как переменные PS. Для остальной части этого обсуждения (и в более раннем обсуждении выше) я буду предполагать, что они являются переменными, и буду называть их таковыми. - Хотя они кажутся переменными, они не перечислены в
Variable:
PSDrive, как большинство переменных. Таким образом, он ведет себя как$env
"переменная", которая также не указана вVariable:
, У меня есть чувство, если бы я мог найти документацию о$env
тогда я бы тоже понял эти объекты. - В некотором смысле они ведут себя как указатели на объекты файловой системы. Например, если есть имя файла
readme.txt
содержащий текст "Привет, мир!" на PSDrive с именемcode
, то все следующие возможные взаимодействия с Powershell.
Получить содержимое файла.
λ ${code:\readme.txt}
Hello, world!
Просто чтобы доказать, что тип приведенного выше результата String
:
λ ${code:\readme.txt} | % { $_.GetType().Name }
String
Попытка использовать это как ссылку на PSDrive не работает хорошо для многих операций, таких как cd
:
C:\
λ cd ${code:}
At line:1 char:4
+ cd ${code:}
+ ~~~~~~~~
Variable reference is not valid. The variable name is missing.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : InvalidBracedVariableReference
Я мог бы продолжать, но я в тупике. Если я пройду $code:
(или же $env:
в этом отношении) Get-Member
Я получаю сообщение об ошибке Variable reference is not valid
,
Так что, черт возьми, такие "переменные", как $env
а также $<PSDrive>:
(такие как $code:
)? Это выражения? Встроенные выражения? Какой-то объект? Спасибо за любую помощь.
2 ответа
То, что вы видите, - это переменная нотация пространства имен, которая представляет собой основанный на переменных способ доступа к содержимому элементов в дисках PowerShell, базовый поставщик которых реализует доступ на основе содержимого (т. Е. Реализует IContentCmdletProvider
интерфейс).
Общий синтаксис:
${<drive>:<path>} # same as: Get-Content <drive>:<path>
${<drive>:<path>} = ... # same as: Set-Content <drive>:<path> -Value ...
Вмещающий {...}
не нужны, если оба <drive>
имя и <path>
может синтаксически служить именем переменной; например:
$env:HOME # no {...} needed
${env:ProgramFiles(x86)} # {...} needed due to "(" and ")"
На практике, начиная с Windows PowerShell v5.1, следующие поставщики встроенных накопителей поддерживают нотацию переменных пространства имен:
- Окружающая среда
Env:
) - Функция (привод
Function:
) - Псевдоним (диск
Alias:
) - Файловая система (диски
C:
...) - Переменная (диск
Variable:
) - хотя практически бессмысленно, учитывая, что пропуская часть диска по умолчанию обращается к переменным (например,$variable:HOME
так же, как просто$HOME
).
Из них Env:
диск, безусловно, наиболее часто используется с нотацией переменных пространства имен, хотя большинство пользователей не знают, что лежит в основе ссылок на переменные среды, таких как $env:HOME
,
Иногда вы видите, что он используется с диском файловой системы - например, ${c:\foo\file.txt}
- но тот факт, что вы можете использовать только буквальные пути и что вы не можете контролировать кодировку символов, ограничивает его полезность.
Это позволяет интересные использования, однако; например:
PS> $alias:foreach # Get the definition of alias 'foreach'
ForEach-Object
PS> $function:prompt # Get the body of the 'prompt' function
"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) ";
# .Link
# https://go.microsoft.com/fwlink/?LinkID=225750
# .ExternalHelp System.Management.Automation.dll-help.xml
# Define a function foo that echoes 'hi' and invoke it.
PS> $function:foo = { 'hi' }; foo
hi
Замечания:
Так как
${<drive>:<path>}
а также${<drive>:<path>} = <value>
эквивалентныGet-Content -Path <drive>:<path>
а такжеSet-Content -Path <drive>:<path> <value>
, пути интерпретируются как подстановочные выражения (потому что это то, что-Path
делает, в отличие от-LiteralPath
), что может вызвать проблемы с путями, которые выглядят как символы подстановки - см. этот ответ для примера и обходного пути.На момент написания статьи нотация переменных пространства имен официально еще не документирована, но эта проблема GitHub предлагает сделать это.
$env
переменные окружения Windows, такие же, какие вы получаете, когда делаете SET
в командной строке. Есть несколько, которые специфичны для PS.
Переменная предоставляет доступ к провайдеру среды. https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-6
Есть несколько других провайдеров, которые описаны здесь: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_providers?view=powershell-6
Как сказано в документе:
Модель для представления данных - диск файловой системы. Чтобы использовать данные, предоставляемые поставщиком, вы просматриваете их, перемещаетесь по ним и изменяете их, как если бы они были данными на жестком диске. Поэтому наиболее важной информацией о поставщике является имя диска, который он поддерживает.