1

我正在尝试从文本文件中读取值并将它们作为变量保存在我的脚本中使用。

此配置文件包含字符串、整数、布尔值和一个可以包含字符串、整数和布尔值的数组。

当我直接声明变量时,我没有问题。我的脚本按预期运行。但是,当我阅读配置文件并尝试基于该文件创建变量时,我只会得到声明为字符串的变量。

这会以我想要的格式创建我的配置文件。

Function Create-Config() {
    If (!(Test-Path config.txt)) {
        $currentlocation=Get-Location
        $parentfolder=(get-item $currentlocation).parent.FullName
        New-Item config.txt -ItemType "file"
        Add-Content config.txt "SERVER_NAME=MyServer"
        Add-Content config.txt "SERVER_LOCATION=$currentlocation"
        Add-Content config.txt "BACKUP_LOCATION=$parentfolder\backup"
        Add-Content config.txt "CRAFTBUKKIT=craftbukkit.jar"
        Add-Content config.txt "JAVA_FLAGS=-Xmx1G"
        Add-Content config.txt "CRAFTBUKKIT_OPTIONS=-o True -p 1337"
        Add-Content config.txt "TEST_DEPENDENCIES=True"
        Add-Content config.txt "DELETE_LOG=True"
        Add-Content config.txt "TAKE_BACKUP=True"
        Add-Content config.txt "RESTART_PAUSE=5"
   }

}

但是,要么我需要更改创建配置文件的方式,要么更改导入这些变量的方式。我希望配置文件尽可能简单。我正在使用此代码导入值:

Function Load-Variables() {
    Get-Content config.txt | Foreach-Object {
        $var = $_.Split('=')
        New-Variable -Name $var[0] -Scope Script -Value $var[1]
    }
}

如您所见,我没有显式设置变量,因为配置中的变量是不同的类型(布尔值、整数、数组、字符串)。但是,PowerShell 将这些都作为字符串导入。我可以单独导入所有变量(我可能必须这样做),但我仍然觉得我会被困在数组上。

如果我使用此命令声明数组:

New-Variable -Name CRAFTBUKKIT_OPTIONS -Option Constant -Value ([array]@('-o',$true,'-p',25565))

我得到了我想要的,但我需要从配置文件中导入它,而不是在我的脚本中声明变量。java 程序有点挑剔,所以我不能只将该值作为字符串导入,否则它将无法正确传递并且这些选项会被忽略。我发现它工作的唯一方法是将它作为一个数组(如上定义)。我还想指出,可能会出现比我的示例中更多的配置文件选项。

我不确定什么是更好的方法 - 导入要正确声明的变量(我想做的事情),或者假设它们不能作为字符串以外的任何东西导入,然后将该字符串解析为正确的变量类型。

我尝试过事先声明变量并使用 Set-Variable 命令设置值,但这不起作用。看起来我的变量从一开始就使用 Get-Content 作为字符串而不是正确的类型导入。

完整的脚本在这里: https ://gist.github.com/TnTBass/4692f2a00fade7887ce4

4

2 回答 2

3

有什么帮助吗?

$types = @{
SERVER_NAME         = {$args[0]}
SERVER_LOCATION     = {$args[0]}
BACKUP_LOCATION     = {$args[0]}
CRAFTBUKKIT         = {$args[0]}
JAVA_FLAGS          = {$args[0]}
CRAFTBUKKIT_OPTIONS = { ($args[0].split(' ')[0] -as [string]),
                        ([bool]::Parse($args[0].split(' ')[1])),
                        ($args[0].split(' ')[2] -as [string]),
                        ($args[0].split(' ')[3] -as [int]) }
TEST_DEPENDENCIES   = {[bool]::Parse($args[0])}
DELETE_LOG          = {[bool]::Parse($args[0])}
TAKE_BACKUP         = {[bool]::Parse($args[0])}
RESTART_PAUSE       = {$args[0] -as [int]}
}

$ht = [ordered]@{}
gc config.txt |
  foreach {
           $parts = $_.split('=').trim()
           $ht[$parts[0]] = &$types[$parts[0]] $parts[1]
           }

New-object PSObject -Property $ht


SERVER_NAME         : MyServer
SERVER_LOCATION     : C:\testfiles
BACKUP_LOCATION     : C:\\backup
CRAFTBUKKIT         : craftbukkit.jar
JAVA_FLAGS          : -Xmx1G
CRAFTBUKKIT_OPTIONS : {-o, True, -p, 1337}
TEST_DEPENDENCIES   : True
DELETE_LOG          : True
TAKE_BACKUP         : True
RESTART_PAUSE       : 5

$types 哈希表使用配置文件中的参数名称作为键,以及定义需要对从文件中读取的参数的字符串值执行的键入和数据转换的脚本块。当从文件中读入每一行时,脚本的这一部分:

   $parts = $_.split('=').trim()
   $ht[$parts[0]] = &$types[$parts[0]] $parts[1]

在“=”处拆分它,然后查找该参数的脚本块并使用该值作为参数调用它。结果存储在哈希表 ($ht) 中,然后用于创建对象。如果这更适合您的应用程序,您可以省略对象创建并仅使用哈希表来传递您的配置值。

您可能需要添加一些错误捕获来测试生产工作的输入数据和/或结果值。但我认为脚本块的哈希表是一种非常简洁的方式来呈现输入和转换,并且如果您需要进行更改,应该相当直观地阅读并且易于在脚本中维护。前 5 个参数是字符串参数,只是按原样返回,但为了清楚起见,您可以在脚本块中将它们显式转换为 [string]。

于 2013-11-08T19:48:01.387 回答
0

当然,Powershell 将变量值作为字符串处理。那是因为它无法在没有额外帮助的情况下将字符串“1337”与整数 1337 区分开来。为了指定数据类型,您需要一些元数据。有一种专门的格式——XML。现在,您不需要自己创建 XML 文件。有管理 Powershell 对象序列化Import-CliXML的cmdlet。Export-CliXML

例如,可以将配置设置保存在哈希表中并像这样序列化它,

$cfgSettings = @{ 
"currentlocation" = "my current location";
"parentfolder" = "my backup location";
"SERVER_NAME" = "MyServer";
"SERVER_LOCATION" = $currentlocation;
"BACKUP_LOCATION" = "$parentfolder\backup";
"CRAFTBUKKIT" = "craftbukkit.jar";
"JAVA_FLAGS" = "-Xmx1G";
"CRAFTBUKKIT_OPTIONS" = "-o True -p 1337";
"TEST_DEPENDENCIES" = $true;
"DELETE_LOG" = $true;
"TAKE_BACKUP" = $true;
"RESTART_PAUSE" = 5
}

Export-Clixml -Path myConf.xml -InputObject $cfgSettings

该文件包含具有数据类型的序列化哈希表。例如,DELETE_LOG 是布尔值,RESTART_PAUSE 是 int 等等:

  <En>
    <S N="Key">DELETE_LOG</S>
    <B N="Value">true</B>
  </En>
  <En>
    <S N="Key">RESTART_PAUSE</S>
    <I32 N="Value">5</I32>
  </En>
  <En>
    <S N="Key">JAVA_FLAGS</S>
    <S N="Value">-Xmx1G</S>
  </En>

重新填充和访问设置哈希表也不难:

$config = Import-CliXML myConf.xml
$config["DELETE_LOG"] # NB! Case sensitive, "delete_log" is different a key!
True

编辑

根据如何创建数组,这里是一个使用反序列化数据的示例。

拆分选项并序列化值:

$config = @{
"CRAFTBUKKIT_OPTION1" = "-o" ;
"CRAFTBUKKIT_OPTION2" = $true ;
"CRAFTBUKKIT_OPTION3" = "-p" ;
"CRAFTBUKKIT_OPTION4" = 1337 }
Export-Clixml -InputObject $config -Path .\temp\conf.xml

反序列化这些值并从中创建一个数组:

$config2 = Import-Clixml C:\temp\conf.xml
$array = @( 
$config2["CRAFTBUKKIT_OPTION1"], 
$config2["CRAFTBUKKIT_OPTION2"], 
$config2["CRAFTBUKKIT_OPTION3"], 
$config2["CRAFTBUKKIT_OPTION4"])

使用类型信息打印数组内容:

$array | % { $("{0} {1}" -f $_, ($_.gettype().name)) }
# Output
-o String
True Boolean
-p String
1337 Int32
于 2013-11-08T19:36:02.837 回答