7
votes

Trouver et remplacer dans un gros fichier

Je veux trouver un morceau de texte dans un grand fichier XML et souhaitez remplacer un autre texte. La taille du fichier est autour (50 Go). Je veux faire cela dans la ligne de commande. Je regarde PowerShell et je veux savoir s'il peut gérer la grande taille. De plus, je voudrais savoir la syntaxe pour échapper aux opérateurs clés de PowerShell. Je suis un PowerShell Newbie

Actuellement, j'essaie actuellement quelque chose comme ça, mais cela ne l'aime pas xxx

Le texte que je veux remplacer est xmlns: xsi = "http://www.w3.org/2001/xmlschema-Instance" avec chaîne vide "".

questions

  1. POWERSHELL POINT POWERSHELL GRAND Fichiers
  2. Comment puis-je appeler le Script PowerShell de la ligne de commande
  3. la syntaxe de la touche d'échappement opérateurs dans PowerShell et la liste des principaux opérateurs de PowerShell.
  4. Je ne veux pas que le remplacement se produise dans mémoire et préférez le streaming en supposant qui n'apportera pas le serveur à ses genoux.
  5. y a-t-il d'autres approches que je peux prendre (différents Outils / Stratégie?)

    merci


0 commentaires

5 Réponses :


4
votes

Cela ne l'aime pas parce que vous ne pouvez pas lire à partir d'un fichier et en écriture en même temps en utilisant le contenu de get-contenu / set. Je recommande d'utiliser un fichier Temp, puis à la fin, renommez FILE1.XML vers File1.xml.bak et renommez le fichier Temp to File1.xml.

  1. Oui tant que vous n'essayez pas de charger l'ensemble du fichier à la fois. La ligne par ligne fonctionnera mais va être un peu lent. Utilisez le paramètre -ReadCount et définissez-le sur 1000 pour améliorer les performances.
  2. Quelle ligne de commande? PowerShell? Si tel est le cas, vous pouvez appeler votre script comme si tel que . \ Myscript.ps1 et s'il utilise des paramètres, alors c: \ users \ joe \ myscript.ps1 c: \ temp \ file1.xml < / code>.
  3. En général pour les regextes, je voudrais utiliser des guillemets simples si vous n'avez pas besoin de référencer des variables PowerShell. Ensuite, il vous suffit de vous soucier de l'évacuation de Regex et de ne pas trop s'échapper de PowerShell. Si vous avez besoin d'utiliser des guillemets, le caractère de la coche arrière est le caractère d'évacuation en double guilleme. "` $ p1 est défini sur $ PS1 ". Dans votre exemple, la citation unique simplifie votre regex à (Remarque: Les barres obliques ne sont pas des métacaracteurs dans Regex):

    'xmlns: xsi = "http://www.w3.org/2001/xmlschema-Instance"'

  4. Vous voulez absolument diffuser cela puisque 50GB ne s'intègre pas dans la mémoire. Cependant, cela pose un problème si vous traitez la ligne de ligne. Et si le texte que vous souhaitez remplacer est divisé sur plusieurs lignes?

  5. Si vous n'avez pas le problème de la ligne de scission, je pense que PowerShell peut gérer cela.

4 commentaires

@Keith, vous faites vraiment confiance à PowerShell;) Je m'inquiéterais peut-être de OutofMemoryException car 50 Go est assez grand pour collecter de petites fuites de mémoire .. Juste une supposition. Personnellement, j'utiliserais directement fichier.open et travaillez avec un flux et comparez manuellement (pas de regex).


Et ne devrait-on pas utiliser une sorte d'API XML pour faire cela? Juste une pensée. Dunno si SAX ou Stax sont disponibles dans .NET; Je travaille trop rarement avec XML, mais une chaîne remplacer les sons ne va pas pour cela.


.NET dispose d'un lecteur de style de curseur en avant (xmlreader / xmltextreader) - un mécanisme de traction qui est un peu différent de l'approche Push Sax. C'est un peu fastidieux mais un bon moyen d'aller lorsque tout le document XML ne s'intègre pas dans la mémoire.


@stej, bon point sur la regex - ne semble pas l'air nécessaire et pourrait être remplacé par une chaîne.replace ().



-2
votes

Le caractère d'échappement dans les chaînes PowerShell est le backttick (`), pas la barre oblique inverse (\). Je donnerais un exemple, mais le backtick est également utilisé par le marquage Wiki. : (

La seule chose que vous devriez avoir à vous échapper est les citations - les périodes et telles devraient être correctes sans.


0 commentaires

13
votes

J'ai eu un besoin similaire (et un manque similaire d'expérience PowerShell), mais j'ai cobblé une réponse complète des autres réponses sur cette page plus un peu plus de recherches.

Je voulais aussi éviter le traitement des regex, puisque je ne voulais pas Il en a besoin - juste une simple chaîne remplacer - mais sur un fichier volumineux, je ne le voulais donc pas chargé dans la mémoire. P>

Voici la commande que j'ai utilisée (ajout de lisibilités pour la lisibilité): P>

Get-Content sourcefile.txt
    | Foreach-Object {$_.Replace('http://example.com', 'http://another.example.com')}
    | Set-Content result.txt


2 commentaires

Sur un fichier PS de 200 Mo a pris 3,5 Go de RAM. 30% de CPU quand je l'ai tué.


peut-être vérifier -readcount ou -raw HAPYSYSADM.COM/2014/10/...



1
votes

Ceci est ma prise, construisant certaines des autres réponses ici: xxx

et appelé comme si: xxx


0 commentaires

5
votes

En plus de vous inquiéter de la lecture du fichier dans des morceaux pour éviter de le charger en mémoire, vous devez jeter un disque si vous ne stockez pas le contenu total du fichier résultant en mémoire.

Get-Content sourcefile.txt -ReadCount 10000 | 
    Foreach-Object {
        $line = $_.Replace('http://example.com', 'http://another.example.com')
        Add-Content -Path result.txt -Value $line
    }


2 commentaires

Compte tenu de la valeur par défaut de ReadCount comme 1, est-ce une amélioration? Certains fichiers contiennent tout sur une ligne (telle que JSON minimisé).


@Duck_Tape_coder, je me sens comme ça dépendrait de la rapidité de la vitesse. Je vais faire des tests et mettre à jour la réponse si vous enlevez / la modification du nombre de lecture a un meilleur effet. Je vais aussi regarder dans d'autres options que j'ai conscientes depuis que j'ai posté cette réponse.