Какой тип объекта $ <drivename>: (например, `$ code:`) в Powershell? - PullRequest
2 голосов
/ 07 марта 2019

Сегодня я использовал автозаполнение табуляции для имени переменной в 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, содержащее текст «Hello, world!» на 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 ]

3 голосов
/ 07 марта 2019

Вы видите нотацию переменной пространства имен , которая является основанным на переменных способом доступа к содержимому элементов в дисках PowerShell , чей базовый поставщик реализует доступ на основе содержимого (т. е. реализует интерфейс IContentCmdletProvider).

Общий синтаксис:

${<drive>:<path>}       # same as: Get-Content <drive>:<path>

${<drive>:<path>} = ... # same as: Set-Content <drive>:<path> -Value ...

Вложение {...} не обязательно, если имя <drive> и <path> могут синтаксически служить именем переменной; e.g.:

$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} - но тот факт, что вы можете использовать только литерал путей и что вы не можете контролировать кодировку символов, ограничивает его полезность.

Это позволяет интересное использование, однако; e.g.:

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 предлагает сделать это.

1 голос
/ 07 марта 2019

$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

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

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

...