Pergunta

Eu tenho um arquivo parecido com este:
uma,1
b,2
c,3
uma,4
b,5
c,6
(...repetir milhares de linhas)

Como posso transpor isso para isso?
abc
1,2,3
4,5,6

Obrigado

Foi útil?

Solução

Aqui está uma frase de força bruta do inferno que fará isso:

PS> Get-Content foo.txt | 
      Foreach -Begin {$names=@();$values=@();$hdr=$false;$OFS=',';
                      function output { if (!$hdr) {"$names"; $global:hdr=$true}
                                        "$values";
                                        $global:names=@();$global:values=@()}} 
              -Process {$n,$v = $_ -split ',';
                        if ($names -contains $n) {output};
                        $names+=$n; $values+=$v } 
              -End {output}
a,b,c
1,2,3
4,5,6

Não é o que eu chamaria de elegante, mas deve ajudar você.Isso deve copiar/colar corretamente como está.No entanto, se você reformatá-lo para o que é mostrado acima, você precisará colocar crases após a última curva nos blocos de script Iniciar e Processar.Este script requer o PowerShell 2.0, pois depende do novo operador -split.

Essa abordagem faz uso intenso do cmdlet Foreach-Object.Normalmente, quando você usa Foreach-Object (o alias é Foreach) no pipeline, você especifica apenas um bloco de script assim:

Get-Process | Foreach {$_.HandleCount}

Isso imprime a contagem de identificadores para cada processo.Este uso de Foreach-Object usa o scriptblock -Process implicitamente, o que significa que ele é executado uma vez para cada objeto que recebe do pipeline.Agora, e se quisermos somar todos os identificadores de cada processo?Ignore o fato de que você poderia simplesmente usar Measure-Object HandleCount -Sum para fazer isso, mostrarei como o Foreach-Object pode fazer isso.Como você pode ver na solução original para esse problema, Foreach pode usar um scriptblock Begin que é executado uma vez para o primeiro objeto no pipeline e um scripblock End que é executado quando não há mais objetos no pipeline.Veja como você pode totalizar a contagem de identificadores usando Foreach-Object:

gps | Foreach -Begin {$sum=0} -Process {$sum += $_.HandleCount } -End {$sum}

Relacionando isso à solução do problema, no bloco de script Begin eu inicializo algumas variáveis ​​para conter o array de nomes e valores, bem como um bool ($hdr) que me diz se o cabeçalho foi ou não gerado (queremos apenas gerar isso uma vez).A próxima coisa um tanto surpreendente é que eu também declaro uma função (saída) no bloco de script Begin que chamo dos blocos de script Process e End para gerar o conjunto atual de dados armazenados em $names e $values.

O único outro truque é que o bloco de script Process usa o operador -contains para ver se o nome do campo da linha atual já foi visto antes.Nesse caso, produza os nomes e valores atuais e redefina essas matrizes para vazias.Caso contrário, basta armazenar o nome e o valor nas matrizes apropriadas para que possam ser salvos posteriormente.

Aliás, o motivo pelo qual a função de saída precisa usar o global:O especificador nas variáveis ​​é que o PowerShell executa uma abordagem "cópia na gravação" quando um escopo aninhado modifica uma variável definida fora de seu escopo.No entanto, quando realmente queremos que essa modificação ocorra em um escopo mais alto, temos que dizer ao PowerShell que, usando um modificador como global:ou roteiro:.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top