Comment puis-je remplacer chaque occurrence d'une chaîne dans un fichier par PowerShell?

en utilisant PowerShell, je veux remplacer toutes les occurrences exactes de [MYID] dans un fichier donné par MyValue . Quelle est la meilleure façon de le faire?

215
demandé sur Cœur 2013-06-17 13:29:35

11 réponses

utilisation (version V3):

(Get-Content c:\temp\test.txt).replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt

ou pour V2:

(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt
317
répondu Loïc MICHEL 2015-11-19 22:55:31
(Get-Content file.txt) | 
Foreach-Object {$_ -replace '\[MYID\]','MyValue'}  | 
Out-File file.txt

noter les parenthèses autour de (Get-Content file.txt) est requis:

sans la parenthèse le contenu est lu, une ligne à la fois, et coule le long du pipeline jusqu'à ce qu'il atteigne out-file ou set-content, qui tente d'écrire dans le même fichier, mais il est déjà ouvert par get-content et vous obtenez une erreur. La parenthèse fait que l'opération de lecture de contenu est effectuée une fois (ouvert, lu et fermé). Seulement alors, quand toutes les lignes ont été lire, ils arrivent un à un, et quand ils atteignent la dernière commande dans le pipeline ils peuvent être écrites dans le fichier. C'est le même que $contenu=contenu; $contenu | où ...

78
répondu Shay Levy 2015-04-19 23:59:53

je préfère utiliser la classe File-class de .NET et ses méthodes statiques comme dans l'exemple suivant.

$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)

ceci a l'avantage de travailler avec une seule chaîne de caractères au lieu d'une chaîne de caractères comme avec Get-Content . Les méthodes prennent également soin de l'encodage du fichier (UTF-8 BOM , etc.) sans avoir à prendre soin, la plupart du temps.

aussi les méthodes ne gâchent pas la ligne les terminaisons (terminaisons de ligne Unix qui pourraient être utilisées) en contraste avec un algorithme utilisant Get-Content et piping jusqu'à Set-Content .

donc pour moi: moins de choses qui pourraient casser au fil des ans.

une chose peu connue lorsque vous utilisez les classes .NET est que lorsque vous avez tapé" [System.IO.Fichier]:: "dans la fenêtre PowerShell, vous pouvez appuyer sur la touche Tab pour passer à travers les méthodes.

59
répondu rominator007 2015-07-13 15:51:56

celui ci-dessus ne s'exécute que pour "un seul fichier", mais vous pouvez également l'Exécuter pour plusieurs fichiers dans votre dossier:

Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
     (Get-Content $_ | ForEach  { $_ -replace '[MYID]', 'MyValue' }) |
     Set-Content $_
}
17
répondu John V Hobbs Jr 2016-09-28 19:16:50

vous pourriez essayer quelque chose comme ceci:

$path = "C:\testFile.txt"
$word = "searchword"
$replacement = "ReplacementText"
$text = get-content $path 
$newText = $text -replace $word,$replacement
$newText > $path
9
répondu Richard 2013-06-17 09:43:44

C'est ce que j'utilise, mais il est lent sur de gros fichiers texte.

get-content $pathToFile | % { $_ -replace $stringToReplace, $replaceWith } | set-content $pathToFile

si vous remplacez des chaînes de caractères dans des fichiers texte volumineux et que la vitesse est un problème, cherchez à utiliser le système .IO.StreamReader and System.IO.StreamWriter .

try
{
   $reader = [System.IO.StreamReader] $pathToFile
   $data = $reader.ReadToEnd()
   $reader.close()
}
finally
{
   if ($reader -ne $null)
   {
       $reader.dispose()
   }
}

$data = $data -replace $stringToReplace, $replaceWith

try
{
   $writer = [System.IO.StreamWriter] $pathToFile
   $writer.write($data)
   $writer.close()
}
finally
{
   if ($writer -ne $null)
   {
       $writer.dispose()
   }
}

(Le code ci-dessus n'a pas été testé.)

il y a probablement une façon plus élégante d'utiliser StreamReader et StreamWriter pour remplacer du texte dans un document, mais cela devrait vous donner un bon point de départ.

6
répondu Darrell Lloyd Harvey 2015-08-31 17:44:01

cela a fonctionné pour moi en utilisant le répertoire de travail courant dans PowerShell. Vous devez utiliser la propriété FullName , sinon elle ne fonctionnera pas dans la version 5 de PowerShell. J'avais besoin de changer la version cible .net framework dans tous mes fichiers CSPROJ .

gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
 Set-Content "$($_.FullName)"}
0
répondu SliverNinja - MSFT 2017-05-28 22:18:00

après avoir trop cherché, j'ai trouvé la ligne la plus simple pour faire ceci sans changer le encodage est:

Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext
0
répondu Mohamad Osama 2017-08-19 16:11:19

un peu vieux et différent, car j'avais besoin de changer une certaine ligne dans toutes les instances d'un nom de fichier particulier.

aussi, Set-Content ne retournait pas des résultats cohérents, donc j'ai dû recourir à Out-File .

Code ci-dessous:


$FileName =''
$OldLine = ''
$NewLine = ''
$Drives = Get-PSDrive -PSProvider FileSystem
foreach ($Drive in $Drives) {
    Push-Location $Drive.Root
        Get-ChildItem -Filter "$FileName" -Recurse | ForEach { 
            (Get-Content $_.FullName).Replace($OldLine, $NewLine) | Out-File $_.FullName
        }
    Pop-Location
}

C'est ce qui a fonctionné le mieux pour moi sur cette version PowerShell:

Majeur.Mineur.Construire.Révision

5.1.16299.98

0
répondu Kalin Tashev 2017-12-19 15:05:54

crédit à @rominator007

j'ai enveloppé dans une fonction (car vous pouvez l'utiliser à nouveau)

function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
    $content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
    [System.IO.File]::WriteAllText("$FullPathToFile", $content)
}

NOTE: Ce n'est pas sensible à la casse!!!!!

Voir ce post: de la Chaîne.Remplacer ignorant la casse

0
répondu Kolob Canyon 2018-09-01 03:37:58

petite correction pour la commande Set-Content. Si la chaîne recherchée n'est pas trouvée, la commande Set-Content vide le fichier cible.

vous pouvez d'abord vérifier si la chaîne que vous recherchez existe ou non. Si non, elle ne remplacera pas quoi que ce soit.

If (select-string -path "c:\Windows\System32\drivers\etc\hosts" -pattern "String to look for") `
    {(Get-Content c:\Windows\System32\drivers\etc\hosts).replace('String to look for', 'String to replace with') | Set-Content c:\Windows\System32\drivers\etc\hosts}
    Else{"Nothing happened"}
-1
répondu dan D 2017-03-28 16:01:18