通过散列循环,或在PowerShell中使用数组?

时间:2012-01-26 07:45:18

标签: powershell

我正在使用这个(简化的)代码块从SQL Server中使用bcp提取一组表。

$OutputDirectory = "c:\junk\"
$ServerOption =   "-SServerName"
$TargetDatabase = "Content.dbo."

$ExtractTables = @(
    "Page"
    , "ChecklistItemCategory"
    , "ChecklistItem"
    )

for ($i=0; $i -le $ExtractTables.Length – 1; $i++)  {
    $InputFullTableName = "$TargetDatabase$($ExtractTables[$i])"
    $OutputFullFileName = "$OutputDirectory$($ExtractTables[$i])"
    bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
}

效果很好,但现在有些表需要通过视图提取,有些则不需要。所以我需要一个像这样的数据结构:

"Page"                      "vExtractPage"
, "ChecklistItemCategory"   "ChecklistItemCategory"
, "ChecklistItem"           "vExtractChecklistItem"

我在看哈希,但我找不到任何关于如何循环哈希的东西。这里做什么是正确的?也许只是使用一个数组,但两个值都用空格分隔?

或者我错过了一些明显的东西?

8 个答案:

答案 0 :(得分:169)

脚本不喜欢速记;它的可读性较差。 %{}运算符被认为是简写。以下是如何在脚本中完成可读性和可重用性:

变量设置

PS> $hash = @{
    a = 1
    b = 2
    c = 3
}
PS> $hash

Name                           Value
----                           -----
c                              3
b                              2
a                              1

选项1:GetEnumerator()

注:个人喜好;语法更容易阅读

GetEnumerator()方法将如下所示完成:

foreach ($h in $hash.GetEnumerator()) {
    Write-Host "$($h.Name): $($h.Value)"
}

输出:

c: 3
b: 2
a: 1

选项2:密钥

Keys方法将如下所示完成:

foreach ($h in $hash.Keys) {
    Write-Host "${h}: $($hash.Item($h))"
}

输出:

c: 3
b: 2
a: 1

其他信息

小心排序哈希表...

Sort-Object可能会将其更改为数组:

PS> $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object


PS> $hash = $hash.GetEnumerator() | Sort-Object Name
PS> $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

This and other PowerShell looping are available on my blog.

答案 1 :(得分:93)

Christian的答案效果很好,并展示了如何使用GetEnumerator方法遍历每个哈希表项。您还可以使用keys属性进行循环。以下是一个示例:

$hash = @{
    a = 1
    b = 2
    c = 3
}
$hash.Keys | % { "key = $_ , value = " + $hash.Item($_) }

输出:

key = c , value = 3
key = a , value = 1
key = b , value = 2

答案 2 :(得分:5)

关于循环哈希:

$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"}
$Q.GETENUMERATOR() | % { $_.VALUE }
1
3
2

$Q.GETENUMERATOR() | % { $_.key }
ONE
THREE
TWO

答案 3 :(得分:4)

您也可以在没有变量的情况下执行此操作

@{
  'foo' = 222
  'bar' = 333
  'baz' = 444
  'qux' = 555
} | % getEnumerator | % {
  $_.key
  $_.value
}

答案 4 :(得分:4)

Here is another quick way, just using the key as an index into the hash table to get the value:

$hash = @{
    'a' = 1;
    'b' = 2;
    'c' = 3
};

foreach($key in $hash.keys) {
    Write-Host ("Key = " + $key + " and Value = " + $hash[$key]);
}

答案 5 :(得分:3)

也可以使用子表达式运算符 $( ) 给出短遍历,它返回一个或多个语句的结果。

func didTapped(index: Int) {
   index = index 
}

结果:

$hash = @{ a = 1; b = 2; c = 3}

forEach($y in $hash.Keys){
    Write-Host "$y -> $($hash[$y])"
}

答案 6 :(得分:2)

我更喜欢使用带有管道的枚举器方法的此变体,因为您不必在foreach中引用哈希表(在PowerShell 5中进行了测试):

Solarium library version: 3.0.0 - Ping query successful


    Fatal error:  Uncaught Solarium\Exception\UnexpectedValueException: Solr JSON response could not be decoded in C:\Bitnami\wampstack-7.0.0RC7-\apache2\htdocs\vendor\solarium\solarium\library\Solarium\Core\Query\Result\Result.php:158
    Stack trace:
    #0 C:\Bitnami\wampstack-7.0.0RC7-\apache2\htdocs\ping4.php(34): Solarium\Core\Query\Result\Result->getData()
    #1 {main}
      thrown in C:\Bitnami\wampstack-7.0.0RC7-\apache2\htdocs\vendor\solarium\solarium\library\Solarium\Core\Query\Result\Result.php on line 158

输出:

public static string SendRecOne(string dataToSvr)
    {
        TcpClient client = new TcpClient(SERVER_NAME, PORT);
        #region SendRequest
        int ByteCount = Encoding.ASCII.GetByteCount(dataToSvr); //How much bytes?
        byte[] ByteBuffer = new byte[1024]; //initialize byte array
        ByteBuffer = Encoding.ASCII.GetBytes(dataToSvr);
        NetworkStream stream = client.GetStream();
        stream.Write(ByteBuffer, 0, ByteBuffer.Length);
        #endregion
        #region Receive Response
        //byte[] responseData = new byte[client.ReceiveBufferSize];
        //int bytesRead = stream.Read(responseData, 0, client.ReceiveBufferSize);
        int i;
        string ToReturn = null;
        ByteBuffer = new byte[ByteBuffer.Length];
        MemoryStream ms = new MemoryStream();
        while (true)
        {
            if (stream.DataAvailable)
            {
                while ((i = stream.Read(ByteBuffer, 0, ByteBuffer.Length)) != 0)
                {
                    ms.Write(ByteBuffer, 0, ByteBuffer.Length);
                    if (stream.DataAvailable)
                        continue;
                    else
                        break;
                }
                ToReturn = Encoding.ASCII.GetString(ms.ToArray());
                return ToReturn;
            }
        }
        #endregion

现在,尚未对值进行故意排序,枚举器仅以相反的顺序返回对象。

但是,由于这是一条管道,因此我现在可以按值对从枚举器接收到的对象进行排序:

$hash = @{
    'a' = 3
    'b' = 2
    'c' = 1
}
$hash.getEnumerator() | foreach {
    Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}

输出:

Key = c and Value = 1
Key = b and Value = 2
Key = a and Value = 3

答案 7 :(得分:1)

如果您使用的是PowerShell v3,则可以使用JSON而不是哈希表,并将其转换为Convert-FromJson的对象:

@'
[
    {
        FileName = "Page";
        ObjectName = "vExtractPage";
    },
    {
        ObjectName = "ChecklistItemCategory";
    },
    {
        ObjectName = "ChecklistItem";
    },
]
'@ | 
    Convert-FromJson |
    ForEach-Object {
        $InputFullTableName = '{0}{1}' -f $TargetDatabase,$_.ObjectName

        # In strict mode, you can't reference a property that doesn't exist, 
        #so check if it has an explicit filename firest.
        $outputFileName = $_.ObjectName
        if( $_ | Get-Member FileName )
        {
            $outputFileName = $_.FileName
        }
        $OutputFullFileName = Join-Path $OutputDirectory $outputFileName

        bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
    }