2013-03-03 2 views
6

Я хочу импортировать внешнюю функцию из файла, а не преобразовывать ее в модуль (у нас есть сотни файлов для каждой функции, поэтому относиться ко всем их как к модулям является чрезмерным) ,Dot-sourcing функции из файла в глобальную область внутри функции

Вот код пояснения. Обратите внимание, что у меня есть дополнительная логика в функции импорта, например, добавление корневой папки сценариев и проверка существования файла и специальная ошибка броска, чтобы избежать дублирования кода в каждом скрипте, который требует такого импорта.

C: \ Repository \ Foo.ps1:

Function Foo { 
    Write-Host 'Hello world!' 
} 

C: \ InvocationTest.ps1:

# Wrapper func 
Function Import-Function ($Name) { 
    # Checks and exception throwing are omitted 
    . "C:\Repository\$name.ps1" 

    # Foo function can be invoked in this scope 
} 

# Wrapped import 
Import-Function -Name 'Foo' 
Foo   # Exception: The term 'Foo' is not recognized 

# Direct import 
. "C:\Repository\Foo.ps1" 
Foo   # 'Hello world!' 

Есть ли трюк, чтобы точка источника в глобальном масштабе?

ответ

4

Вы не можете заставить сценарий работать в родительской области, но вы можете создать функцию в глобальной области видимости, явно просматривая ее.

Возможно, вам понравится эта работа?

# Wrapper func 
Function Import-Function ($Path) { 
    # Checks and exception throwing are omitted 
    $script = Get-Content $Path 
    $Script -replace '^function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)', 'function Global:$1' 
    .([scriptblock]::Create($script)) 

} 

The above regex нацелен только корневые функции (функции выравниваются по левому краю, нет пустого пространства слева от слова function). В целях выявления всех функций, независимо от расстояния (в том числе подфункций), измените $Script -replace линию:

$Script -replace '^\s*function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)','function Global:$1' 
+0

Большое спасибо, этот приятный хач работает. Я добавил несколько незначительных исправлений, чтобы заставить его работать, если вы не возражаете. –

+0

Не возражайте. Я просто пытался передать идею, а не обязательно готовое решение. – mjolinor

+0

@AntonPurin вы можете обновить ответ, включив в него свои «незначительные исправления»? –

0

Я не могу вспомнить способ запуска функции в глобальной области действия прямо сейчас. Вы могли бы сделать что-то вроде этого:

$name = "myscript" 

$myimportcode= { 
    # Checks and exception throwing are omitted 
    . .\$name.ps1 
    # Foo function can be invoked in this scope 
} 

Invoke-Expression -Command $myimportcode.ToString() 

При преобразовании ScriptBlock в строку .ToString(), переменная будет расширяться.

0

Вы можете изменить функции, которые определены в файлах дот-источниках, так что они определены в глобальный масштаб:

function Global:Get-SomeThing { 
    # ... 
} 

Когда точка источника, что из функции, функция, определенная в файле дот источников будет глобальным. Не сказать, что это лучшая идея, это еще одна возможность.

Смежные вопросы