Powershell: Fornece uma maneira independente de plataforma para determinar a temperatura. diretório, por exemplo, por meio de uma variável automática.

Criado em 11 jul. 2017  ·  67Comentários  ·  Fonte: PowerShell/PowerShell

Relacionado: # 3442 e # 4215

As várias plataformas suportadas têm diferentes maneiras nativas de determinar o diretório no qual armazenar arquivos e diretórios temporários:

  • Janelas:

    • $env:TEMP

  • Mac OS:

    • $env:TMPDIR

  • Linux:

    • /tmp

Atualmente, não existe uma maneira independente de plataforma de se referir a esse diretório, o que é complicado.

Uma variável automática, digamos $TEMP , poderia fornecer essa abstração.

Dados ambientais

PowerShell Core v6.0.0-beta.3
Area-Cmdlets-Utility Committee-Reviewed Issue-Discussion Resolution-Fixed

Todos 67 comentários

que tal algo como: (New-TemporaryFile) .DirectoryName

@ lukeb1961 : Isso realmente produz o diretório temporário específico da plataforma, mas tem um efeito colateral indesejado: New-TemporaryFile invariavelmente _cria_ o arquivo cuja representação [System.IO.FileInfo] ele produz.

Em outras palavras: toda vez que você executa (New-TemporaryFile).DirectoryName , você deixa um arquivo temporário não utilizado para trás.

Além disso, é uma abordagem computacionalmente cara.

Já discutimos isso em poucas palavras. Obrigado por abrir a edição.

Internamente já temos "TemporaryDirectory", apenas "GetTemporaryDirectory ()" e "CreateTemporaryDirectory ()". Poderíamos tornar isso público.

Que tal usar $

@Liturgist : $Env:TMP não é uma opção, porque não é aconselhável (a) fazer com que o PowerShell _define_ _environment_ automaticamente ou (b) fingir que existem variáveis ​​de ambiente inexistentes.

Uma variável automática _PowerShell_, como $TMP é uma opção, no entanto, deve-se ter em mente que a introdução retroativa de variáveis ​​automáticas é tecnicamente uma alteração importante.

Se fôssemos pela rota variável, teria que ser algo como $ interop: TEMP para evitar colisão de nomes. Uma variável é provavelmente mais fácil de usar em scripts do que uma API, embora possamos certamente oferecer suporte a ambas.

Em https://github.com/PowerShell/PowerShell/issues/3571 , sugeri outras variáveis ​​além de TEMP

@ SteveL-MSFT:

Bom ponto; um namespace $interop: é de fato uma maneira de evitar colisões.

Se dermos um passo para trás: se quisermos que o PowerShell se torne a língua franca do mundo do shell, realmente queremos enquadrar as coisas como "interoperabilidade"?

Que tal confiar nas variáveis ​​automáticas do PowerShell para fazer a coisa certa (TM) _genericamente_, que exigiria um namespace como $ps: ?

@ mklement0 o prefixo / namespace $ps: foi proposto antes. Seria bom se tivéssemos usado isso desde o início :)

Pessoalmente, prefiro $ps: exatamente pelo seu raciocínio. Talvez este possa ser um ponto de discussão na próxima Chamada da Comunidade.

cc @ PowerShell / powershell-Committee

Fico feliz em ouvir isso, @ SteveL-MSFT.

Por falar no assunto, acho que um namespace separado para todas as variáveis ​​_preference_ também seria benéfico, como $pspref:

A ressalva é que, embora as colisões sejam muito menos prováveis ​​do que com nomes de variáveis ​​não qualificados, alguém _poderia_ ter feito algo como o seguinte:

# Define custom drive 'ps:'
New-PSDrive 'ps' FileSystem '/tmp'; Get-ChildItem ps:

@iSazonov :

Isso funciona, mas é difícil de lembrar e difícil de digitar.
É bom saber como uma solução alternativa, no entanto.

Se tivermos New-TemporaryFile usuários esperam Get-TemporaryPath de Get-TemporaryDirectory .

@iSazonov :

Como o termo _path_ é ambíguo (embora seja usado na API .NET para se referir a um caminho de _diretório_ neste caso), minha preferência seria Get-TemporaryDirectory e certamente não me importaria de ter esse cmdlet .

Dito isso, um cmdlet é um pouco pesado para algo que retorna uma única informação sem variações de funcionalidade.

Considere o Get-Host / $Host duo existente: Você já se viu usando Get-Host vez de $Host ?

$ps:Temp presumivelmente retornaria um local estático para colocar coisas temporárias. Get-TemporaryDirectory presumivelmente criaria uma nova pasta em $ps:temp . Pessoalmente, acho que ter uma unidade temp: PS pode ser mais útil. Talvez seja limpo automaticamente na saída do processo.

temp: - boa ideia. Se aceitarmos, devemos ter cmdlets para isso. E acredito que podemos aprimorar os cmdlets * -PSDrive.

temp: - inicializado em [io.path]::GetTempPath() .

Nós faríamos temp: opcionalmente por runpaces.

Eu preferiria uma maneira consistente de mapear variáveis ​​de ambiente que são basicamente as mesmas, apenas expressas de forma diferente. Estamos dizendo que mapearemos todas as variáveis ​​de caminho para unidades, como Home: \?

@ mklement0 - Não tenho certeza de por que Env:TMP é uma má ideia. Com relação a a) PowerShell cria Env:PSModulePath . Com relação a b), não sei de quais variáveis ​​o PowerShell estaria fingindo. Eu gostaria de entender.

@Liturgist Acho que a noção é que qualquer coisa no namespace $Env: deve ser apenas variáveis ​​de ambiente reais nessa plataforma. Também seria muito confuso ter $Env:TEMP e $Env:TMP definidos ao mesmo tempo. Como posso saber qual é o que devo usar para executar no Linux, OSX e Windows apenas olhando para ele?

As propostas para um namespace ou unidade separada eliminam esse problema, pois permite que o PowerShell tenha suas próprias variáveis ​​comumente definidas que podem ser usadas em várias plataformas e não bloqueiam o acesso às variáveis ​​de ambiente real.

Outra ideia para um namespace poderia ser $PSEnv: . Tem um significado implícito de que qualquer coisa nesse namespace vem do PowerShell e não do sistema. Então, você pode mapear de forma limpa todas as variáveis ​​de ambiente comuns e tornar mais fácil ver o que está disponível para uso no IntelliSense.

@ dragonwolf83 - Env:PSModulePath seria movido para PSEnv:PSModulePath ? Concordo plenamente que não deve haver várias variáveis, como Env:TEMP e Env:TMP . Deve haver um bom e vamos com ele. Ter PSEnv:TEMP ou PSEnv:TMP seria ótimo.

Para ir com New-TemporaryFile , seria útil ter New-TemporaryDirectory . Para continuar, seria útil ter um parâmetro -Path em New-TemporaryFile para especificar o diretório no qual criar o arquivo temporário.

Não, não acho que a equipe do PowerShell moveria $Env:PSModulePath por três motivos.

  1. Seria uma mudança significativa que não agrega nenhum valor
  2. É uma variável de ambiente real, portanto não faria sentido movê-la.
  3. Não há necessidade de forçar um mapeamento desta variável de ambiente para trabalhar em plataforma cruzada. É algo que o PowerShell pode adicionar às Variáveis ​​de ambiente ao instalar o PowerShell porque eles possuem essa variável.

Em outras palavras, ele existe exatamente onde pertence.

Dê uma olhada na imagem abaixo. Mostra as variáveis ​​de ambiente definidas em meu sistema Windows. Tem TEMP e TMP como variáveis ​​de ambiente para o caminho Temp do meu usuário. Também possui PSModulePath. Portanto, todas essas outras variáveis, eu esperaria ver no namespace $Env: . Você pode acessar cmd e ver que todas essas variáveis, incluindo PSModulePath, existem lá também.

image

@Liturgist :

Para adicionar comentários úteis de @ dragonwolf83 e responder ao seu comentário dirigido a mim:

Não sei de quais variáveis ​​o PowerShell estaria fingindo. Eu gostaria de entender.

Meu ponto talvez flagrantemente óbvio-não-preciso-ser-dito era que, na ausência do PowerShell, realmente _definindo_ tal variável de ambiente (o que, como declarado, seria imprudente - veja também abaixo), o PowerShell deveria 't _pretender que existe_.


O PowerShell respeita / define apenas _duas_ variáveis ​​de ambiente , de acordo com Get-Help about_Environment_Variables :

  • $env:PSExecutionPolicyPreference , quando definido _externally_, _before_ invocando powershell , pode ser usado para definir a política de execução para a sessão (atualmente: apenas Windows PowerShell).

    • Se não for definida externamente, essa variável não será definida na sessão do PowerShell e o valor configurado padrão / persistentemente se aplica.
  • $env:PSModulePath , quando definido _externally_, _before_ invocando powershell , pode ser usado para definir os diretórios para o caminho de pesquisa de módulo do PowerShell (a lista de diretórios em que o PowerShell procura por módulos carregados por _name_ apenas).

    • Se não for definido externamente, o PowerShell o define com uma lista de diretórios padrão (current-user, all-users, mas _não_ sistema).

      • No meu sistema W10 / PSv5.1, este env. variável _é_ predefinida, como um env de _ nível de sistema_. variável, com o diretório _system_ modules, $PSHOME/Modules , com os diretórios padrão restantes sendo definidos na inicialização do PowerShell, _prepended_ para o dir system-modules.
      • Parece que definir um diretório não padrão na variável de nível de sistema faz com que ele seja injetado após o valor do usuário atual.

      • As instalações do PowerShell Core em plataformas Unix não têm variáveis ​​predefinidas.

    • Se definido externamente no nível de _processo_ (com set PSModulePath=... & powershell ... de cmd.exe ou PSModulePath=... powershell ... de shells semelhantes a POSIX):

      • O Windows PowerShell v5.1 usa _just_ o valor externo _as-is_.
      • PowerShell Core _injects_ o valor externo na lista de diretórios padrão, após o valor do usuário atual.

Essas variáveis ​​são variáveis ​​de _ambiente_ por um bom motivo: elas permitem que você controle o comportamento de inicialização do PowerShell _externamente_.

Por outro lado, NÃO há um bom motivo para definir o diretório para arquivos temporários e diretórios como uma variável _ambiente_:

  • O valor é estático e pode ser derivado (especificamente da plataforma) do ambiente _existente_, _ padronizado_ ( $env:TMP no Windows, $env:TMPDIR no macOS) / convenções de plataforma ( /tmp no Linux )

    • Não há um bom motivo para expor esse valor a _processos filho_ por meio do _ambiente_, porque (a) se esses processos filho não forem processos do PowerShell, eles não saberão quais variáveis ​​de ambiente o PowerShell define e (b) qualquer sessão do PowerShell pode derivar o valor de forma independente.

    • Por outro lado, qualquer variável de ambiente que o PowerShell defina carrega o risco de uma colisão de nome com uma variável de mesmo nome usada de forma diferente por outros ambientes. Embora esse problema possa ser mitigado com um prefixo de nome _por convenção_ - como PS - a melhor abordagem é evitar definir variáveis ​​de ambiente completamente, se elas não forem necessárias.

Se um leitor estiver familiarizado principalmente com cmd.exe , vale a pena apontar que cmd.exe -ao contrário de PowerShell e shells semelhantes a POSIX no Unix - conhece _apenas_ variáveis ​​de ambiente: qualquer variável que você definir em cmd.exe é _implicitamente também_ uma variável de ambiente, enquanto PowerShell e shells semelhantes a POSIX distinguem entre variáveis ​​_shell_ específicas de sessão ( por exemplo, $foo no PowerShell) e variáveis ​​explicitamente designadas como tal (por exemplo, $env:foo no PowerShell).


Eu definitivamente gosto da ideia de _multiple_ namespaces para variáveis ​​automáticas do PowerShell (como o $PSPref: sugerido para variáveis ​​de preferência), então colocar o diretório para arquivos temporários em $PSEnv: é uma boa ideia, embora nós ' teria que deixar claro que - apesar da presença da palavra 'Env' - essas não são variáveis ​​de _ambiente_ reais no sentido do sistema estabelecido (acessível a todos os processos filho, independentemente de qual executável está sendo executado).

Parece que houve uma discussão boa o suficiente para que talvez este devesse ser um RFC?

Eu definitivamente gosto da ideia de vários namespaces para variáveis ​​automáticas do PowerShell

Em [io.path] :: GetTempPath () o [io.path] é um namespace - devemos introduzir um namespace "nativo" do Powershell como $PSEnv: ?

@ SteveL-MSFT:

Antes de abordarmos um RFC, deixe-me tentar resumir o que considero serem os casos de uso e talvez obter uma melhor compreensão do escopo de tal RFC:

  • [x] Crie um _arquivo_ temporário (no local apropriado para a plataforma, com um nome exclusivo gerado aleatoriamente):

    • New-TemporaryFile já fornece isso.

    • [] Crie um _arquivo_ temporário com uma _extensão de nome de arquivo específica_ - consulte # 4215

  • [] Crie um _diretório_ temporário (no local apropriado para a plataforma, com um nome exclusivo gerado aleatoriamente):

    • # 3442 solicita esta habilidade, propondo que um switch -Directory seja adicionado a New-TemporaryFile
  • [] _Determine_ o _path_ do diretório apropriado para a plataforma (raiz) para arquivos e diretórios temporários.

    • O assunto principal _este_ problema, com a introdução de novos _namespace (s) _ controlados pelo PowerShell _ sendo considerada.
  • [] Ter a capacidade de criar implicitamente um arquivo temporário com escopo de comando e de exclusão automática, de modo a apresentar a saída de um comando como um arquivo ao chamar utilitários externos (semelhante a uma substituição de processo Bash) - consulte # 4284

  • [] Possivelmente forneça uma unidade temp: definida implicitamente.

    • Eu acho que isso só valeria a pena se essa unidade fosse _script / function-scoped_ ao invés de session-scoped; ou seja, se um script / função pudesse gravar nesta unidade sem medo de colisões de nomes, semelhante à unidade de limpeza automática TestDrive: que Pester fornece.

    • Dito isso, temo que isso seria muito caro e que o escopo não seja tão claro como no caso de Pester.

Quanto à introdução de namespaces controlados por PowerShell :

Observe que a notação de namespace atual - por exemplo, $env:PATH é na verdade baseada em _ter um drive PS subjacente_: todos os $<prefix>: "prefixos" atualmente suportados referem-se a _drives do mesmo nome_; por exemplo, $env:HOME é igual a (Get-Item Env:/Home).Value .

Se agora introduzirmos namespaces como $PSEnv: sem um drive subjacente - e um drive subjacente seria sem dúvida um exagero - estaremos nos afastando desse modelo.
Pessoalmente, não acho que seja um problema, mas deve ser uma decisão consciente e documentada.


Então, o que uma RFC deve cobrir?

  • Introdução de namespaces controlados pelo PowerShell?

    • Apenas para variáveis ​​de "ambiente" com escopo PS ou, como mencionado, talvez também para variáveis ​​de preferência?
  • Uma unidade temp: implicitamente definida?

Eu poderia lidar com o primeiro, mas não tenho certeza se posso chegar a uma abordagem sensata para o último (e pode não valer a pena fazer).

@ mklement0 obrigado por resumir todas as diferentes discussões relacionadas. Acho que apenas definir o escopo da seção Motivation da RFC para o primeiro item é suficiente. Você pode declarar explicitamente que temp: está fora do escopo do RFC.

@ mklement0 -

Eu preferiria ter New-TemporaryDirectory vez de adicionar um switch -Directory a New-TemporaryFile . New-TemporaryDirectory é mais óbvio e detectável. Se ambos não forem possíveis, voto em New-TemporaryDirectory .

Obrigado, @Liturgist.

Ouvi dizer que você é New-TemporaryDirectory (embora exista a tradição orgulhosa e confusa do Unix de chamar _qualquer_ item do sistema de arquivos de "arquivo" ....).

No extremo oposto do espectro, você poderia argumentar (como alguém já tem, mas eu esquecer de onde) que deveria haver apenas um genérico New-TemporaryItem cmdlet com -Type File e -Type Directory parâmetros (concebivelmente, cada provedor de unidade poderia implementar seus próprios locais temporários, embora entre os que vêm com o PowerShell, isso realmente só faça sentido para o provedor FileSystem ).

De qualquer forma, sugiro que você faça sua voz ser ouvida no número 3442.


@ SteveL-MSFT: Obrigado pela orientação, mas apesar de minha disposição inicial de lidar com este RFC, gostaria de me retirar desta [auto-] atribuição.
Eu espero que outra pessoa assuma isso.

Depois de alguma discussão, @ PowerShell / powershell-Committee está se inclinando para um cmdlet, em vez de um novo namespace variável, a fim de fornecer melhor capacidade de descoberta, preenchimento com tab, etc.

No momento, o método estático .NET funciona para fazer isso, mas queremos, eventualmente, estabelecer um padrão melhor com cmdlets. Eu prevejo que eles viveriam em um módulo de "compatibilidade", enviado na Galeria, que funcionaria em 3/4/5 e que poderia eventualmente ser enviado como parte do 6.x.

Podemos ter uma implementação interna desses tipos de coisas flutuando. Deixe-me encontrar alguns outros MSFTies e voltar. Por enquanto, porém, acho que isso deve ser movido para 6.1.0

Além disso, esta é exatamente a classe de problemas que se pretende resolver por https://github.com/PowerShell/PowerShell-RFC/blob/master/1-Draft/RFC0019-PowerShell-Core-Interop-Module.md (escrito por @darwinJS). Seria incrível se mais pessoas pudessem fornecer comentários em PowerShell / PowerShell-RFC # 68

@ mklement0 - Obrigado por sua amável resposta. Se a rota do cmdlet for desejada, por que não adicionar um switch -Temporary a New-Item ? Procurarei pelo # 3442.

@joeyaiello : Obrigado pela indicação para o RFC e pela discussão com ele.

inclinado para um cmdlet em vez de um novo namespace de variável

Não acho que os dois sejam mutuamente exclusivos.

Para dar um exemplo do contexto desta discussão específica:

É útil ter cmdlets que o protegem de ter que saber a localização de uma plataforma para temp. arquivos (como New-TemporaryFile ) _e_, ocasionalmente, ter a capacidade de determinar aquele local explicitamente (por exemplo, $ps:TEMP ).
(Além disso, pelo menos com relação ao preenchimento da guia $ps: e $pspref: deve funcionar bem.)

@Liturgist : Gosto da ideia. New-TemporaryFile sempre me pareceu um desastre.

PS, como um aparte: Embora a capacidade de chamar métodos .NET diretamente seja sempre uma ótima opção (uma que diferencia o PowerShell de outros shells), ela só deve ser necessária em cenários incomuns, devido à sintaxe diferente, ao conhecimento avançado requer e que haja dragões .

PPS (último - juro dedinho, @joeyaiello):

Eu disse anteriormente que a introdução de namespaces como $ps: e $pspref: sem uma _drive_ subjacente seria um desvio da notação de namespace atual, sugerindo que a introdução de tais unidades pode ser muito pesada.

Por outro lado, se esses novos namespaces _ fossem_ apoiados por uma unidade, isso resolveria as questões de descoberta, porque você poderia então executar comandos como Get-ChildItem ps: e Get-ChildItem pspref: para descobrir todas essas variáveis.

@ mklement0 - outra abordagem é um

gci variable:PREPEND* 

Um prefixo também evitaria a etapa necessária de descobrir um terceiro namespace para dados variáveis ​​(depois de variable: e env :) - esperançosamente antes de você começar a criar suas próprias variáveis.

Provavelmente deveríamos mover esta conversa para o RFC real para não perder esses pensamentos.

Prefiro $psvar vez de $pspref .
Também é descobrir descrições - Get-Help $psvar:pstableversion .
Liste todas as variáveis ​​de sistema Get-Variable -ListPowerShellEngineVariables .

Com relação a temp .
Por que não discutimos cenários comuns?
Para que serve um arquivo temporário? Para que serve um diretório temporário?
Por que um roteirista precisa pensar sobre isso? Podemos excluir isso?
Se estamos _explicitamente_ usando diretórios temporários, temos que juntar / analisar os caminhos. Podemos excluir isso e usar diretórios temporários _implicitamente_?

Cenário 1:

  1. Crie um arquivo temporário.
  2. Use o arquivo.
  3. Esqueça o arquivo - esperamos que um sistema remova o arquivo. Se olharmos para% temp% ou% WINDIR% temp, vemos toneladas de arquivos não excluídos.

Conclusão 1: Diretório temporário explícito não necessário. Devemos adicionar um aprimoramento para remover nossos arquivos temporários.

Cenário 2:

  1. Crie um diretório temporário para um escopo (bloco / script / módulo / instância de classe).
  2. Crie um arquivo temporário no diretório temporário.
  3. Use o arquivo.
  4. Esqueça o arquivo e o diretório - esperamos que um sistema remova o arquivo e o diretório.

Conclusão 2: Diretório temporário explícito não necessário. Devemos adicionar um aprimoramento para remover nossos diretórios temporários.

Cenário 3:

  1. Crie um diretório temporário
  2. Extraia um arquivo no diretório temporário. Aqui temos que usar o prefixo temporário.
  3. Processe os arquivos.
  4. Esqueça os arquivos e o diretório - esperamos que um sistema remova os arquivos e o diretório.

Conclusão 3: diretório temporário explícito _possivelmente_ necessário. Devemos adicionar um aprimoramento para remover nossos diretórios temporários.

Conclusão comum.

  1. Devemos limpar nossos arquivos / diretórios temporários.
    A solução pode ser - o aplicativo PowerShell cria um subdiretório em% temp% como ps-{New-GUID} , cria arquivos / diretórios temporários nele e remove o diretório na hora de encerramento.
  2. Podemos ver que apenas o Cenário 3 requer diretório temporário explícito e junção com um prefixo temporário.
    Devemos abordar o cenário? Se sim, uma solução do tipo Pester parece ótima - poderíamos nos basear nos cmdlets * -Drive para criar diretórios temporários com escopo em% temp% e usá-los como prefixo temporário. Também abre uma maneira de introduzir temps com escopo definido.

Apenas alguns comentários.

Este tópico foi além da solicitação original, que é simplesmente ter um método agnóstico de plataforma para determinar a pasta TEMP. Talvez as discussões sobre a criação de arquivos e pastas temporários efêmeros devam ser outro RFC?

Em segundo lugar, aqui está o código que uso para criar a variável TEMP e as variáveis ​​COMPUTERNAME no PowerShell Core. Até agora, todos os meus exemplos são para tornar as abstrações do Windows presentes no Linux, porque tenho muito código escrito para o Windows.

Além disso, para saber quais variáveis ​​transportar, basicamente tento julgar o que é MUITO comum em meus scripts e existe como uma entidade no lado do Linux (por exemplo, hostname, temp), mas simplesmente não é exposto da maneira que meu script espera.

Em minha mente, a ideia por trás da compatibilidade seria facilitar a adoção por meio de [a] reutilização de código existente, [b] capacidade de reutilizar abstrações familiares e [c] capacidade de escrever scripts de plataforma cruzada.

Espero que [a] não seja esquecido por uma perspectiva excessivamente greenfield, pois é esta que eu mais usei.

If ((Test-Path variable:IsWindows) -AND !$IsWindows)
{
  If (Test-Path '/tmp')
  {
    write-output 'running on PowerShell Core, setting up TEMP environment variable'
    $env:temp = '/tmp'
    $env:computername = hostname
    $env:computername = ($env:computername).split('.')[0]
  }
  Else
  {
    Throw "Cannot find standard temp folder '/tmp' on non-windows platform."
  }
}

@DarwinJS : Sim, o impulso de seu RFC é bem diferente, então eu concordo que o que a discussão aqui direcionou (apesar de seu foco inicial ser apenas _um_ pedaço de informação do ambiente) deve ser seu próprio RFC.

Em resumo:

  • seu RFC tenta tornar mais fácil a portabilidade de scripts baseados no Windows existentes, fornecendo um polyfill, como um módulo opcional.

  • o que a discussão aqui se direcionou é tornar as informações abstratas da plataforma sobre o ambiente uma parte integrante do PS Core, como um novo namespace, não restringido pelos idiomas existentes nas plataformas suportadas (apenas me ocorreu que talvez $psenv é preferível a $ps ).

    • Discussões secundárias que surgiram:

      • Fornecendo um novo namespace para as variáveis ​​_preference_ do PowerShell (OK, então foi apenas _I_ que falou sobre isso :)

      • Novo cmdlet [parâmetros] que estendem a capacidade de criar itens temporários para _diretórios_ e com uma determinada extensão de nome de arquivo (ambos cobertos por problemas preexistentes).

      • Limpeza automática de arquivos / dirs temporários.

As duas abordagens não são mutuamente exclusivas.

Minha única preocupação com a sua abordagem específica é que você está criando variáveis ​​de _ambiente_ em plataformas Unix, que são vistas por todos os processos filhos, embora as variáveis ​​sejam usadas apenas _PowerShell-internamente_ (para reafirmar uma preocupação expressa em um comentário anterior ).

Não tenho certeza se entendo por que é importante se os processos filho não reconhecem as variáveis ​​de ambiente que não usam - é uma coisa bastante comum para software e scripts definir variáveis ​​de ambiente personalizadas que os processos filho - incluindo binários do sistema operacional - irão ignorar.

No geral, acho que ajudará na adoção se NÃO houver um novo tipo de dados no PowerShell para fazer coisas básicas como identificar a localização temporária do disco. "Variáveis ​​de ambiente" e "Variáveis ​​de linguagem" parecem normais e familiares para ambos os lados da casa.

Se um namespace for escolhido, eu não usaria "psenv". Se você tiver que virar e não explicar a implicação universalmente óbvia da string "env" - parece um antipadrão de aprendizagem. Sempre que a desambiguação pode ser incorporada na nomenclatura inicial, ela economiza bilhões de repetições verbais e escritas do seguinte qualificador:

"Apesar das implicações do nome 'psenv', ele não tem nada a ver com as variáveis ​​de ambiente do sistema operacional."

Eu percebo que seu polyfill depende da definição de variáveis ​​de ambiente, e dado que nem TEMP nem COMPUTERNAME são variáveis ​​de ambiente definidas por POSIX, e dado que estamos falando de um módulo opcional, isso provavelmente bem.

De maneira mais geral, a preocupação não é com os processos filho _ignorando_ variáveis ​​de ambiente, mas com _conflitos de nomenclatura_: utilitários diferentes usando uma variável de ambiente com o mesmo nome para finalidades diferentes, sem o conhecimento um do outro.

O namespace das variáveis ​​de ambiente é compartilhado e não restringido de nenhuma maneira (exceto sintaticamente), e a única maneira de evitar colisões é adotando a nomenclatura _convenções_ - um prefixo como PS sendo unidirecional - mas não uma maneira infalível .

Portanto, a abordagem mais robusta é evitar o uso de variáveis ​​de ambiente completamente, se elas não forem estritamente necessárias - o que é o caso aqui (cada sessão pode derivar os valores do ambiente existente).

Quanto à introdução do que você chama de um novo tipo de dados: familiaridade é ótimo e ajuda aqueles que estão familiarizados com _uma_ maneira antiga de fazer as coisas, mas não é uma grande base para um shell que aspira a ser inerentemente multi-plataforma - e especialmente um shell cujo sucesso é devido a fazer as coisas de uma maneira nova e superior.

Para escrever scripts multi-plataforma, os usuários precisam de _abstrações_ que possam _confiar_ e, inversamente, não usar essas abstrações irá informá-los de que estão se aventurando em um território específico da plataforma (o que pode ser perfeitamente adequado, dependendo do caso de uso).

Quanto ao namespace psenv : Para mim, o prefixo ps sugere que se refere a um ambiente com escopo _PowerShell_, portanto, _constrói_ o significado estabelecido de env - que irá obviamente continuam a existir como o namespace para variáveis ​​de ambiente genuínas.
Dito isso, os nomes são negociáveis.

Pontos positivos - tenho certeza de que TEMP está pronto para conflitos - então, por ser um módulo de compatibilidade opcional "Win to Linux", o teste de script provavelmente revelaria isso.

A familiaridade não é o único valor dos chamados métodos "antigos" - eles também têm a implementação mais onipresente. E "novas" formas podem ser superadas - na semana passada, ajudei um colega a substituir 13 linhas de código que recebeu de uma grande empresa por uma linha. O novo código usou os CMDLets "* ScheduledJob", excepcionalmente supercomplexos e incompletamente implementados. Se as novas implementações ficarem excessivamente focadas na "pureza do design", elas podem ser um retrocesso. Não estou dizendo que esse seja o caso de propor um novo namespace - apenas que, se a "adotabilidade" não for a vanguarda para uma nova implementação, ela pode acabar sendo uma prateleira.

Outra consideração com o novo espaço de nome é que, se não for retransportado para PSH 5, não será onipresente por algum tempo. Ainda vou precisar "descobrir" se posso contar com o namespace para o código que escrevo que precisa ser PSH 5 / PSH 6 + multiplataforma. Então, vou precisar customizar algo para o PSH 5. Na verdade, o Windows PSH 5 é provavelmente o caso de uso dominante em um futuro próximo.

Mas talvez isso apenas guie a implementação em direção a um módulo para que aqueles que desejam possam executá-lo em versões anteriores a 6?

Nossa discussão se dividiu em três direções principais:

  1. Implementar compatibilidade com versões anteriores e portabilidade de scripts do Windows existentes usando TEMP.
  2. Criação de novas abstrações para TEMP para escrever scripts multi-plataforma.
  3. Melhorando a descoberta de variáveis ​​do PowerShell. # 4394

@ mklement0 Você poderia abrir novo (s) problema (s) (para 1. e 2.) para resumir a dissolução e encerrar o problema?

@iSazonov :

Ref. 1 .: Isso é coberto pelo RFC existente de @DarwinJS .
Re 2: Antes de ressuscitarmos isso, sugiro que obtenhamos clareza sobre a abordagem geral proposta em # 4394.

@DarwinJS :

Outra consideração com o novo espaço de nome é que, se não for retransportado para PSH 5, não será onipresente por algum tempo.

Eu ouvi você, mas manter o controle de qual recurso foi introduzido quando é um desafio inevitável se você quiser inovar.
Um módulo back-port pode realmente ajudar, no entanto.

Eu sugiro que continuemos a conversa no # 4394.

$ env: tmp ou $ env: temp é o caso de uso predominante hoje.

promover isso para outras plataformas é trivial. se você o considera interoperacional ou legado, é irrelevante. ele suporta a predominância de todos os scripts existentes.

Resposta curta: [IO.Path]::GetTempPath() é a ÚNICA resposta.

A ideia de que precisamos proteger as pessoas de aprender sobre .NET é, francamente, boba. Esse método estático é compatível com versões anteriores até o Windows PowerShell 1.0 e não importa quantas melhorias adicionarmos no futuro, ainda é a _uma_ e _apenas_ resposta correta para a pergunta original hoje (mais de um ano depois que ela foi feita e respondida).

No entanto, gosto da _idéia_ de que devemos tornar isso mais fácil no futuro, mesmo que qualquer coisa que venhamos não seja utilizável de forma confiável por anos, porque o PowerShell Core 6 e 6.1 já foram enviados sem ele.

De todas as ideias expressas acima, a única ideia de que gosto (e adoro ) é a ideia de criar uma unidade Temp: e apontá-la para (uma nova pasta com o nome de um GUID e / ou data) no localização retornada por [IO.Path]::GetTempPath() (e talvez limpando-a quando o PowerShell for encerrado). A criação de uma unidade Temp é algo que podemos fazer facilmente no PowerShell Core e em um módulo de compatibilidade para versões já lançadas. É muito improvável que cause um problema (é apenas uma questão de saber se alguém provavelmente criou uma unidade Temp:) e, se isso acontecer, consertá-lo no script onde o problema ocorre seria trivial.

Obviamente, também poderíamos adicionar New-TempDirectory ao comando New-TempFile - mas isso deve ser feito em um módulo externo para começar, para que possa ser inerentemente multiplataforma e compatível com versões anteriores.

Embora eu goste da simplicidade e consistência (muito) de [IO.Path]::GetTempPath() , é imperativo habilitar uma opção de estilo PowerShell para usuários do PowerShell. Para este caso, eu procuro criar uma unidade Temp: com um comando potencialmente relacionado.

Como usuário do PowerShell, sempre gostei do PowerShell estar mais perto de um inglês significativo e simples. Ao NÃO fornecer essa opção e sugerir que as pessoas devem aprender o .NET, a confiança das pessoas será desgastada.

Requerer que um administrador de script use [IO.Path] :: GetTempPath () é obsceno. Não é detectável, não é óbvio e não é powerhell.

Pessoalmente, acredito que promover $ env: tmp é a resposta certa, mas alguém poderia argumentar que também não é PowerShell. Após algumas considerações pessoais, acho que um novo cmdlet Get-TemporaryDirectory (ou um nome semelhante) é a resposta adequada.

Não entendo "New-TempDirectory". O caso de uso normal não é criar um diretório (que New- * indica) - está recuperando o nome de um diretório existente (que Get- * indica).

Estou "meh" sobre uma unidade temp: porque, _para ser detectável_, também requer um ou mais cmdlets. Em vez de oferecer mais "liberdade" ao criador de scripts, uma unidade temporária parece restritiva.

Outra aparência para ser completamente nativo do PowerShell. Podemos evitar o uso explícito de diretórios temporários?

# Create the file in temporary directory
$temp= New-Item -Path xyz.txt -Temporary

# Get the file and copy it to temporary directory
$var2 = Get-Item -Path sample.txt; $tempVar2 = Copy-Item $var2 -Temporary

# The temporary directory is automatically created and dropped for the scope 

Eu sinto que ele deve simplesmente abstrair a plataforma existente com as referências da plataforma do PowerShell mais antigas sendo preferidas para que o código antigo possa ser reutilizado mais facilmente.

Como isso:

If (!(test-path env:temp)) 
{
 If (test-path env:tmpdir) {$env:TEMP = $env:tmpdir}
 elseif (test-path '/var/tmp') {$env:TEMP = '/var/tmp'
}

Voltando ao assunto deste tópico, alguns podem querer obter o que pode ser considerado o diretório tradicional "tmp". Isso poderia retornar [System.IO.Path] :: GetTempPath (). Isso eliminaria a necessidade de um novo namespace ou provedor (ps :, PSEnv :, etc.).

Get-TempDirectory

Se um desenvolvedor quiser usar $ Env: TEMP ou $ Env: TMPDIR ou / tmp, ele está livre para fazer isso. Eles estariam tornando sua plataforma de código dependente.

Os aplicativos precisam de mecanismo para criar diretórios e arquivos exclusivos para armazenar coisas. E se estendêssemos New-Item para poder criar um ou mais diretórios e arquivos temporários. Ele retornaria uma lista dos nomes dos itens. Os nomes dos itens devolvidos já estarão criados e prontos para uso.

New-Item -TempDirectory -NamePrefix [string[]]
New-Item -TempFile -NamePrefix [string[]]

Apenas para resumir a discussão até agora:

Estamos falando de dois casos de uso _complementares_ aqui, embora um seja muito mais importante:

  • (a) _Mais importante_ - mas observe que _não_ é sobre o que se tratava originalmente - precisamos da capacidade de _diretamente_criar_ arquivos temporários e diretórios com caminhos que são garantidos como únicos - sem ter que se preocupar com as especificações - se for um cmdlet cria o arquivo / dir. para você, você não precisa se preocupar com onde ele está armazenado e qual o diretório raiz da plataforma. para arquivos temporários é.

    • New-TemporaryFile já faz isso para _files_.

      • # 4215 sugeriu aprimorá-lo com a capacidade de especificar a extensão do nome do arquivo do caminho do arquivo retornado.

      • @Liturgo , você pode dizer mais sobre quando -NamePrefix seria útil?

    • # 3442 trata do suporte à criação de arquivos temporários. _diretórios_ também.
    • Suportando arquivos e dirs. via New-Item é uma opção (algo que você sugeriu anteriormente em # 3442 também, @Liturgist , com a opção de especificar um diretório de destino para o item temporário), mas dado que temos New-TemporaryFile já, talvez seja mais fácil simplesmente implementar New-TemporaryDirectory para simetria - alternativamente, ambas poderiam ser funções de proxy (semelhantes a mkdir no Windows) que diferem para um New-Item aprimorado.

      • Embora uma unidade temp: pareça tentadora (sem trocadilhos), não acho que seja viável, porque para que seja útil, cada escopo teria que ter sua própria definição de unidade com base em seu próprio diretório exclusivo em para poder criar itens livremente sem risco de colisões de nomes, e gerenciar isso soa como uma sobrecarga muito grande.

      • Por outro lado, a limpeza automática de itens temporários criados explicitamente ao sair do escopo parece mais realista, seguindo as linhas da sugestão de

  • (b) _ Ocasionalmente_ - e esse é o assunto original deste tópico - pode ser útil _conhecer explicitamente o diretório raiz de uma determinada plataforma para criar arquivos temporários e diretórios ._ - por exemplo, para escrever um utilitário que limpa itens temporários sob demanda, ou se você precisa verificar se um determinado caminho se refere a um item temporário.

    • Conforme discutido em detalhes antes , emular ou definir ativamente uma variável de ambiente em plataformas onde eles não têm nenhum significado predefinido é desaconselhável, portanto, tão familiar quanto $env:TEMP é, não é uma solução multi-plataforma adequada.

    • Aparecer este diretório raiz por meio de um Get-Temp[orary]Directory _cmdlet_, como @Liturgist sugere, é definitivamente uma opção.

      • Isso também permitiria suportar a distinção entre as pastas temporárias _user_ e _system_ (Windows e macOS), por meio de parâmetros para solicitar um ou outro (o padrão deve ser o diretório do usuário).
      • Observe que [io.path]::GetTempPath() suporta apenas a recuperação do temporário do _user_. dir., portanto, para o sistema, um [environment]::GetEnvironmentVariable('TEMP', 'Machine') teria que ser usado no Windows e o caminho fixo /tmp no macOS. (Linux não tem essa distinção, embora sistemas semelhantes ao Unix tenham outros tipos de pastas temporárias (consulte https://superuser.com/a/332616/139307), embora provavelmente não tenhamos que nos preocupar em suportá-los )
    • Outra opção (não necessariamente mutuamente exclusiva) é exibir esse caminho de diretório por meio do namespace $sf para pastas especiais propostas em # 6966, ao longo das linhas de $sf:Temporary

      • Observe que isso se basearia na maneira como _CoreFx_ optou por exibir localizações abstratas da plataforma (embora fosse originalmente um recurso exclusivo do Windows): [System.Environment]::GetFolderPath() - seria uma _extensão_, no entanto, dado que a pasta temporária (s) atualmente _não_ estão incluídos lá.

@ mklement0 Obrigado pelo ótimo resumo!

Acho que poderíamos continuar considerando cenários em que todas essas opções podem ser úteis (como "obter um arquivo da web / rede, colocar em temp, processar o arquivo (descompactar / decodificar ...), remover o temp"). Acho que podemos fazer coisas mais maravilhosas do que apenas retornar o diretório temporário.

Eu acertei isso recentemente enquanto brincava com o Azure Functions. Estou tão acostumado a ter TestDrive: no Pester que acho que seria bom ter um drive Temp: montado automaticamente. É claro que, ao contrário de TestDrive: PowerShell não limparia automaticamente. Pensamentos? Deixe-me trabalhar nisso como um recurso experimental ... https://github.com/PowerShell/PowerShell/pull/8696

Com base na discussão acima, o mapeamento simples para Temp: drive parece não ser tão útil e não resolve cenários comuns. (Os usuários podem implementar isso com um comando no perfil. No Azure, é possível simplesmente cd para temp.)
Eu prefiro que o PowerShell Core exponha mais coisas mágicas para os usuários.

Nesse nível, não é especialmente útil, @iSazonov , mas a mudança é útil para futuros autores de módulos, que poderiam simplesmente se referir a Temp: drive em vez de ter que codificar três maneiras diferentes para cobrir todas as plataformas possíveis.

@ SteveL-MSFT - talvez este problema deva ser renomeado e reavaliado para "agnóstico de implementação" para cobrir coisas como shells de nuvem sem implicar que eles são uma plataforma da mesma forma que um SO.

A mudança de nome ajuda a refletir a proposta de valor mais ampla ao trazer implementações sem servidor / não-SO para o escopo.

Obrigado por fazer a curadoria dos problemas, Michael Klement.

Parece que a tradição de um diretório tmp / temp é que cada programa pode usá-lo da maneira que quiser. Isso funciona até a colisão de nomes ou até que haja várias instâncias do mesmo programa. No primeiro caso, os aplicativos devem escolher nomes diferentes. No segundo, o aplicativo pode identificar seus arquivos incluindo informações exclusivas, como seu PID, no nome do arquivo.

(a) Concordo plenamente que, com exclusividade garantida, o aplicativo não deve se preocupar com a localização de um arquivo ou diretório temporário ou com o nome.

Uma restrição deve ser que é possível localizar post-mortem os arquivos e diretórios temporários para permitir a correção de anomalias (localização e correção de bugs). Isso sugere que a limpeza automática de temperatura deve ser uma configuração preferencial?

A sugestão de -NamePrefix foi baseada em um aplicativo ser capaz de identificar seus próprios arquivos temporários em um único pool. Embora a exclusividade garantida elimine isso como um requisito, o desenvolvedor pode encontrar conforto em reconhecer foo_xxxx.tmp, bar_xxxx.tmp, bosh_xxxx.tmp e outros quando vários arquivos temporários estão em uso.

Concordo que, se tivermos New-TemporaryFile, devemos ter New-TemporaryDirectory.

Certamente TEMP: não resolve a pasta temporária única que New-TemporaryDirectory resolveria e as duas são ortogonais. A exclusividade certamente é útil principalmente se você tiver vários processos ou até mesmo espaços de execução, mas isso difere do que o problema original pretendia.

Qual foi o resultado dessa discussão?

New-TemporaryDirectory é https://github.com/PowerShell/PowerShell/issues/3442

Uma unidade Temp: resolve este problema.

@ SteveL-MSFT - Ok. Não vejo uma unidade Temp: de Get-PSDrive em 6.2.1. Estou procurando no lugar errado ou quando a unidade Temp: ficará disponível? # 3442 parece mostrar Waiting - DotNetCore .

O drive Temp: será global para o sistema da mesma forma que um /tmp em * sistemas NIX é atualmente?

Haverá um New-TemporaryDirectory ortogonal com New-TemporaryFile ?

@Liturgist Era um recurso experimental. Agora está em 7.0. Você pode baixar o build diário e encontrá-lo lá. É "global" na sessão do PowerShell.
Não existem planos imediatos para implementar New-TemporaryDirectory - você pode discutir em # 3442.

@Liturgist se você quiser experimentar em 6.2.1, faça o seguinte:

Enable-ExperimentalFeature PSTempDrive

Em seguida, reinicie o pwsh.

: tada: Este problema foi resolvido em # 9872, que agora foi lançado com sucesso como v7.0.0-preview.2 .: tada:

Links úteis:

Estou tentando TEMP:\ mas descobri que não posso usar TEMP:\ diretamente em métodos C # ou ferramentas externas, por exemplo

[System.IO.Compression.ZipFile]::ExtractToDirectory($path, "TEMP:\foo")

ou

unzip foo -d TEMP:\foo

Devo usar Get-Item TEMP:\ ou algo assim para conseguir isso ...

@ LYP951018 :

TEMP: é um drive _PowerShell-only_ (você pode listá-los com Get-PSDrive ) e esses drives não são visíveis para o mundo exterior, incluindo .NET

Você deve traduzir os caminhos baseados em drive PS para seus caminhos de sistema de arquivos "nativos" subjacentes, que é para isso que Convert-Path serve.

Observe que há outra armadilha associada à passagem de caminhos do sistema de arquivos para métodos .NET (embora não para programas externos): .NET normalmente vê um diretório de trabalho diferente do PowerShell, de modo que a passagem de caminhos _relative_ normalmente não funciona como pretendido - é melhor passe _full_ caminhos sempre, com os quais Convert-Path também pode ajudar.

Resumindo: é bom criar o hábito de passar caminhos do sistema de arquivos para métodos .NET via
Convert-Path -LiteralPath .

Se você permanecer no domínio do PowerShell, não enfrentará esse problema; por exemplo, você pode usar Expand-Archive .

Esta página foi útil?
0 / 5 - 0 avaliações