Какой тип объекта в 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

Как сказано в документе:

Модель для представления данных - диск файловой системы. Чтобы использовать данные, предоставляемые поставщиком, вы просматриваете их, перемещаетесь по ним и изменяете их, как если бы они были данными на жестком диске. Поэтому наиболее важной информацией о поставщике является имя диска, который он поддерживает.

Другие вопросы по тегам