web-dev-qa-db-fra.com

Créer un répertoire temporaire dans PowerShell?

PowerShell 5 présente le New-TemporaryFile cmdlet , ce qui est pratique. Comment puis-je faire la même chose mais au lieu d'un fichier, créer un répertoire? Y a t-il New-TemporaryDirectory applet de commande?

25
Michael Kropat

Je pense que cela peut être fait sans boucle en utilisant un GUID pour le nom du répertoire:

function New-TemporaryDirectory {
    $parent = [System.IO.Path]::GetTempPath()
    [string] $name = [System.Guid]::NewGuid()
    New-Item -ItemType Directory -Path (Join-Path $parent $name)
}

Tentative d'origine avec GetRandomFileName

Voici mon port de cette solution C # :

function New-TemporaryDirectory {
    $parent = [System.IO.Path]::GetTempPath()
    $name = [System.IO.Path]::GetRandomFileName()
    New-Item -ItemType Directory -Path (Join-Path $parent $name)
}

Analyse de la possibilité de collision

Quelle est la probabilité que GetRandomFileName renvoie un nom qui existe déjà dans le dossier temporaire?

  • Les noms de fichiers sont renvoyés sous la forme XXXXXXXX.XXX où X peut être une lettre minuscule ou un chiffre.
  • Cela nous donne 36 ^ 11 combinaisons, ce qui en bits est d'environ 2 ^ 56
  • En invoquant le paradoxe d'anniversaire , nous nous attendrions à une collision une fois que nous aurions atteint environ 2 ^ 28 éléments dans le dossier, soit environ 360 millions
  • NTFS prend en charge environ 2 ^ 32 éléments dans un dossier , il est donc possible d'obtenir une collision en utilisant GetRandomFileName

NewGuid d'autre part peut être l'une des 2 ^ 122 possibilités , rendant les collisions presque impossibles.

40
Michael Kropat

J'adore aussi les one-liners, et j'implore un downvote ici. Tout ce que je demande, c'est que vous exprimiez mes propres sentiments négatifs à ce sujet.

New-TemporaryFile | %{ rm $_; mkdir $_ }

Selon le type de puriste que vous êtes, vous pouvez faire %{ mkdir $_-d }, En laissant un espace réservé pour éviter les collisions.

Et il est raisonnable de se tenir sur Join-Path $env:TEMP $(New-Guid) | %{ mkdir $_ } également.

16
nik.shornikov

Voici ma tentative:

function New-TemporaryDirectory {
    $path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())

    #if/while path already exists, generate a new path
    while(Test-Path $path)) {
        $path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
    }

    #create directory with generated path
    New-Item -ItemType Directory -Path $path
}
3
sodawillow

.NET a eu [System.IO.Path]::GetTempFileName() pendant un bon moment; vous pouvez l'utiliser pour générer un fichier (et capturer le nom), puis créer un dossier avec le même nom après avoir supprimé le fichier.

$tempfile = [System.IO.Path]::GetTempFileName();
remove-item $tempfile;
new-item -type directory -path $tempfile;
2
alroc

J'adore un doublures si possible. @alroc .NET a également [System.Guid]::NewGuid()

$temp = [System.Guid]::NewGuid();new-item -type directory -Path d:\$temp

Directory: D:\


Mode                LastWriteTime     Length Name                                                                                                                        
----                -------------     ------ ----                                                                                                                        
d----          1/2/2016  11:47 AM            9f4ef43a-a72a-4d54-9ba4-87a926906948  
2
user4317867

Si vous voulez que la solution de bouclage qui soit garantie sans course ni collision, alors voici:

function New-TemporaryDirectory {
  $parent = [System.IO.Path]::GetTempPath()
  do {
    $name = [System.IO.Path]::GetRandomFileName()
    $item = New-Item -Path $parent -Name $name -ItemType "directory" -ErrorAction SilentlyContinue
  } while (-not $item)
  return $Item.FullName
}

Selon l'analyse de réponse de Michael Kropat , la grande majorité du temps, cela ne passera qu'une seule fois dans la boucle. Il passera rarement deux fois. Il ne passera pratiquement jamais trois fois.

2
John Freeman