web-dev-qa-db-fra.com

PowerShell - Codage par lots de fichiers de changement de lot en UTF-8

J'essaie de faire une chose simple et simple: changer l'encodage de fichiers de n'importe quoi en UTF-8 sans BOM. J'ai trouvé plusieurs scripts qui font cela et le seul qui a vraiment fonctionné pour moi est celui-ci: https://superuser.com/questions/397890/convert-text-files-recursively-to-utf-8-in- Powershell # answer-397915 .

Cela a fonctionné comme prévu, mais j'ai besoin des fichiers générés sans nomenclature. J'ai donc essayé de modifier un peu le script en ajoutant la solution donnée à cette question: Utilisation de PowerShell pour écrire un fichier au format UTF-8 sans la nomenclature

Ceci est mon dernier script:

foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    get-content $i | out-file -encoding $Utf8NoBomEncoding -filepath $dest
}

Le problème est que powershell me renvoie une erreur concernant la ligne System.Text.UTF8Encoding($False) et se plaint d'un paramètre incorrect:

Il n'est pas possible de valider l'argument sur le paramètre 'Encoding'. L'argument "System.Text.UTF8Encoding" n'appartient pas au groupe "unicode, utf7, utf8, utf32, ascii" spécifié par l'attribut ValidateSet.

Je me demande si quelque chose me manque, comme la version PowerShell ou quelque chose comme ça. Je n'avais jamais codé de script Powershell auparavant, alors je suis totalement perdu avec cela. Et je dois changer l'encodage de ces fichiers, il y en a des centaines, je ne voudrais pas le faire moi-même un à un.

En fait, j'utilise la version 2.0 fournie avec Windows 7.

Merci d'avance!

EDIT 1

J'ai essayé le code suivant, suggéré par @LarsTruijens et d'autres publications:

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    $content = get-content $i
    [System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
}

Cela me donne une exception, se plaindre de l'un des paramètres de WriteAllLines: "Exception on calling 'WriteAllLines' with 3 arguments. The value can't be null". Parameter name: contents. Le script crée tous les dossiers, cependant. Mais ils sont tous vides.

EDIT 2

Une chose intéressante à propos de cette erreur est que le paramètre "content" n’est pas nul. Si je produis la valeur de la variable $ content (en utilisant Write-Host), les lignes sont là. Alors, pourquoi devient-il nul lorsqu'il est passé à la méthode WriteAllLines?

EDIT 3

J'ai ajouté une vérification de contenu à la variable, le script ressemble donc à ceci:

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    $content = get-content $i

    if ( $content -ne $null ) {

        [System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
    }
    else {
        Write-Host "No content from: $i"
    }
}

Désormais, chaque itération renvoie le message "Aucun contenu de: $ i", mais le fichier n'est pas vide. Il y a encore une erreur: Get-content: can't find the path 'C:\root\FILENAME.php' because it doesn't exists. Il semble que le système cherche les fichiers dans le répertoire racine et non dans les sous-dossiers. Il semble pouvoir extraire le nom de fichier des dossiers enfants, mais essaie de le lire à partir de la racine.

EDIT 4 - Version de travail finale

Après avoir eu du mal à suivre et à suivre les conseils que je suis arrivé ici, spécialement de @LarsTruijens et @AnsgarWiechers, j'ai finalement réussi. J'ai dû changer la façon dont je récupérais le répertoire à partir de $ PWD et définir des noms fixes pour les dossiers. Après cela, cela a parfaitement fonctionné.

Voilà, pour tous ceux qui pourraient être intéressés:

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
$source = "path"
$destination = "some_folder"

foreach ($i in Get-ChildItem -Recurse -Force) {
    if ($i.PSIsContainer) {
        continue
    }

    $path = $i.DirectoryName -replace $source, $destination
    $name = $i.Fullname -replace $source, $destination

    if ( !(Test-Path $path) ) {
        New-Item -Path $path -ItemType directory
    }

    $content = get-content $i.Fullname

    if ( $content -ne $null ) {

        [System.IO.File]::WriteAllLines($name, $content, $Utf8NoBomEncoding)
    } else {
        Write-Host "No content from: $i"   
    }
}
9
darksoulsong

Vous n'avez pas suivi toute la réponse dans ici . Vous avez oublié la partie WriteAllLines.

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    $content = get-content $i 
    [System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
}
4
Lars Truijens

La moitié de la réponse est dans le message d'erreur. Il vous indique les valeurs possibles acceptées par le paramètre Encoding, dont utf8.

... out-file -encoding utf8
2
Shay Levy

J'ai fait quelques corrections

  • Get-Childitem agit sur $ source
  • replace n'essaie pas d'interpréter $ source comme regex
  • un chemin de résolution
  • aide automatique

et tout emballé dans une applet de commande:

<#
    .SYNOPSIS
        Encode-Utf8

    .DESCRIPTION
        Re-Write all files in a folder in UTF-8

    .PARAMETER Source
        directory path to recursively scan for files

    .PARAMETER Destination
        directory path to write files to 
#>
[CmdletBinding(DefaultParameterSetName="Help")]
Param(
   [Parameter(Mandatory=$true, Position=0, ParameterSetName="Default")]
   [string]
   $Source,

   [Parameter(Mandatory=$true, Position=1, ParameterSetName="Default")]
   [string]
   $Destination,

  [Parameter(Mandatory=$false, Position=0, ParameterSetName="Help")]
   [switch]
   $Help   
)

if($PSCmdlet.ParameterSetName -eq 'Help'){
    Get-Help $MyInvocation.MyCommand.Definition -Detailed
    Exit
}

if($PSBoundParameters['Debug']){
    $DebugPreference = 'Continue'
}

$Source = Resolve-Path $Source

if (-not (Test-Path $Destination)) {
    New-Item -ItemType Directory -Path $Destination -Force | Out-Null
}
$Destination = Resolve-Path $Destination

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)

foreach ($i in Get-ChildItem $Source -Recurse -Force) {
    if ($i.PSIsContainer) {
        continue
    }

    $path = $i.DirectoryName.Replace($Source, $Destination)
    $name = $i.Fullname.Replace($Source, $Destination)

    if ( !(Test-Path $path) ) {
        New-Item -Path $path -ItemType directory
    }

    $content = get-content $i.Fullname

    if ( $content -ne $null ) {
        [System.IO.File]::WriteAllLines($name, $content, $Utf8NoBomEncoding)
    } else {
        Write-Host "No content from: $i"   
    }
}
0
Darcon

Cette approche crée la structure de dossiers complète avant de copier les fichiers dans UTF-8 à partir du répertoire actuel. À la fin, nous échangeons les noms de répertoire parent.

$destination = "..\DestinationFolder"
Remove-item $destination -Recurse -Force
robocopy $PWD $destination /e /xf *.*

foreach($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }
    $originalContent = $i.Fullname
    $dest = $i.Fullname.Replace($PWD, $destination)
    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }
    get-content $originalContent | out-file -encoding utf8 -filepath $dest
}
0
jckhan
  1. Allez dans le répertoire que vous voulez cd c:\MyDirectoryWithCrazyCharacterEncodingAndUnicode
  2. Lancez ce script!

Copiez et collez le script dans vos fenêtres Powershell

 foreach($FileNameInUnicodeOrWhatever in get-childitem)
 {
    $FileName = $FileNameInUnicodeOrWhatever.Name

    $TempFile = "$($FileNameInUnicodeOrWhatever.Name).ASCII"

    get-content $FileNameInUnicodeOrWhatever | out-file $FileNameInUnicodeOrWhatever -Encoding ASCII 

    remove-item $FileNameInUnicodeOrWhatever

    rename-item $TempFile $FileNameInUnicodeOrWhatever

    write-output $FileNameInUnicodeOrWhatever "converted to ASCII ->" $TempFile
}
0
transformer