Question Manipulations sur contenu de fichiers en boucle

Plus d'informations
il y a 16 ans 7 mois #5124 par Eric_K
Bonjour à tous,

J'ai commencé à lire votre livre et je débute avec Powershell. Je suis sur un script depuis trois jours et je bloque sur certains points.
Je travaille sous Windows XP SP3, Powershell V1 et Excel 2003. Voici ce que je voudrais faire :

Je voudrais créer une boucle qui pour chaque fichier dans un seul répertoire et dont le nom commence
par lot et avec l'extension .txt m'exécute les actions suivantes :

- pour chaque fichier lotXX.txt : certaines lignes avec certains caractères soient supprimées
- pour chaque fichier lotXX.txt : certains caractères soient remplacés par d'autres.
- pour chaque fichier lotXX.txt : que sur la première colonne du fichier et sur chaque ligne du fichier apparaisse le nombre représenté par les XX du nom du fichier suivi d'un point virgule.
(Je n'ai pas réussi à trouver comment faire pour effectuer cette manipulation)

Ces fichiers auront comme nom lot1.txt à lotXX.txt. (XX : nombre). La liste n'est pas limitée.
Je peux en avoir plus comme je peux en avoir moins, voire qu'un seul. Je ne connais pas à l'avance
le nombre de fichier lotXX.txt dans le répertoire de travail.

Une fois que ce traitement du contenu des fichiers sera effectué, je voudrais concaténer tous ces fichiers en un seul fichier qui s'appellera lots.txt et supprimer tous les fichiers lot1.txt à lotXX.txt qui ont servi a créer le fichier lots.txt.

Ces traitements sur ces fichiers me permettent d'avoir un fichier pré-formaté en CSV que j'ouvrirai
dans Excel pour ensuite créer un tableau croisé dynamique par l'intermédiaire d'une macro qui s'exécutera à l'ouverture du fichier excel.

J'ai fait un test de script sans faire de boucle sur 2 fichiers (lot1.txt et lot2.txt) et ça fonctionne
(sauf l'insertion sur la première colonne du fichier et sur chaque ligne du fichier du nombre représenté
par les XX du nom du fichier suivi d'un point virgule).

Mais je voudrais pouvoir le faire par boucle sur l'ensemble des fichiers lotXX.txt d'un répertoire sans en connaître le nombre.

Dernière chose : comment fait-on pour scinder des lignes d'un script pour éviter d'avoir des lignes qui
font des Kms de long.

Voici le script :

[code:1]
# Suppression des lignes inutiles et remplacement de caractères sur le fichier lot1.txt
(Get-Content lot1.txt) | Where-Object {$_ -notmatch \"PROPO DE PRIX\"} | Where-Object {$_ -notmatch \"Tty :\"} | Where-Object {$_ -notmatch \"User :\"} | Where-Object {$_ -notmatch \"TOTAL HORS TAXES NET\"} | Where-Object {$_ -notmatch \"- TVA\"} | Foreach-Object {$_ -replace \"\++ \+\|\ \", \"\"} | Foreach-Object {$_ -replace \"\ \|\", \";\"} | Foreach-Object {$_ -replace \"\|\", \";\"} | Foreach-Object {$_ -replace \";\ \", \";\"} | Foreach-Object {$_ -replace \"12D \", \"\"} | Foreach-Object {$_ -replace \"\", \"\"} | Foreach-Object {$_ -replace \";LIG;CODE CAT;DESIGNATION;PU NET TTC;\", \"\"} | Foreach-Object {$_ -replace \";LIG;CODE CAT;DESIGNATION;NET TTC;\", \"\"} | where {$_ -ne \"\"} | Set-Content lot1.txt
# Suppression des lignes inutiles et remplacement de caractères sur le fichier lot2.txt
(Get-Content lot2.txt) | Where-Object {$_ -notmatch \"PROPO DE PRIX\"} | Where-Object {$_ -notmatch \"Tty :\"} | Where-Object {$_ -notmatch \"User :\"} | Where-Object {$_ -notmatch \"TOTAL HORS TAXES NET\"} | Where-Object {$_ -notmatch \"- TVA\"} | Foreach-Object {$_ -replace \"\++ \+\|\ \", \"\"} | Foreach-Object {$_ -replace \"\ \|\", \";\"} | Foreach-Object {$_ -replace \"\|\", \";\"} | Foreach-Object {$_ -replace \";\ \", \";\"} | Foreach-Object {$_ -replace \"12D \", \"\"} | Foreach-Object {$_ -replace \"\", \"\"} | Foreach-Object {$_ -replace \";LIG;CODE CAT;DESIGNATION;PU NET TTC;\", \"\"} | Foreach-Object {$_ -replace \";LIG;CODE CAT;DESIGNATION;NET TTC;\", \"\"} | where {$_ -ne \"\"} | Set-Content lot2.txt
# Concaténation des fichiers lot1.txt et lot2.txt
add-content -path lot1.txt -value (get-content c:\test\lot2.txt)
# Suppression du fichier lot2.txt
remove-item lot2.txt
# Renommage du fichier lot1.txt en lots.txt
rename-item lot1.txt lots.txt
# Ecriture d'un fichier texte avec une ligne correspondant aux en-têtes de colonnes
$entete = [System.IO.File]::CreateText(\"C:\test\entete.txt\"«»)
$entete.WriteLine(\"LOT;LIG;CODE CAT;DESIGNATION;NET TTC;\"«»)
$entete.Close()
# Concaténation des fichiers entete.txt et lots.txt
add-content -path entete.txt -value (get-content c:\test\lots.txt)
# Suppression du fichier lots.txt
remove-item lots.txt
# Vérification de l'existence du fichier lots.csv et suppression s'il existe
if (Test-Path c:\test\lots.csv)
{remove-item c:\test\lots.csv}
# Renommage du fichier entete.txt en lots.csv pour importation dans fichier excel lots_marchés.xlt
move-item entete.txt lots.csv
# Ouverture d'excel et ouverture du fichier Lots_Marchés.xlt
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$workbook=$excel.workbooks.open(\"C:\test\Lots_Marchés.xlt\"«»)
[/code:1]

Le fichier lots_marchés.xlt exécute une macro à son ouverture qui :

- importe les données du fichier lots.csv
- formate les colonnes de nombre en format monétaire
- remplace les / par des , et remplace les . en ,
- exécute une formule sur une colonne pour récupérer la partie entière d'un nombre
- créé un tableau croisé dynamique qui trie les prix des articles par ordre décroissant
- met en couleur bleu les lignes correspondant au total des articles par lots
- applique le format monétaire sur la colonne total

Pour ceux que ça intéresse voici la macro :

[code:1]
Private Sub workbook_open()
'
' Macro1
' Macro1
'

With ActiveSheet.QueryTables.Add(Connection:=\"TEXT;C:\test\lots.csv\", _
Destination:=Range(\"A1\"«»))
.Name = \"lots\"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 1252
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
ActiveWindow.DisplayZeros = False
Columns(\"C:C\"«»).Select
Selection.Replace What:=\"/\", Replacement:=\",\", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Columns(\"E:E\"«»).Select
Selection.Replace What:=\".\", Replacement:=\",\", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Range(\"F2\"«»).Select
ActiveCell.FormulaR1C1 = \"=IF((RC[-3]=99903),MID(RC[-2],3,4),INT(RC[-3]))\"
Range(\"F2\"«»).Select
Selection.AutoFill Destination:=Range(\"F2:F\" & Range(\"E2\"«»).End(xlDown).Row), Type:=xlFillDefault
Range(\"F2:F\" & Range(\"E2\"«»).End(xlDown).Row).Select
Range(\"G2\"«»).Select
ActiveCell.FormulaR1C1 = \"=TRIM(C[-1])\"
Range(\"G2\"«»).Select
Selection.AutoFill Destination:=Range(\"G2:G\" & Range(\"F2\"«»).End(xlDown).Row), Type:=xlFillDefault
Range(\"G2:G\" & Range(\"F2\"«»).End(xlDown).Row).Select
Columns(\"G:G\"«»).Select
Selection.Copy
Columns(\"H:H\"«»).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range(\"I2\"«»).Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = \"1\"
Range(\"I2\"«»).Select
Selection.Copy
Columns(\"H:H\"«»).Select
Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlMultiply, _
SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
Range(\"H1\"«»).Select
ActiveCell.FormulaR1C1 = \"CODE CAT\"
Range(\"F:G,C:C\"«»).Select
Range(\"C1\"«»).Activate
Selection.Delete Shift:=xlToLeft
Range(\"F2\"«»).Select
Selection.ClearContents
Columns(\"E:E\"«»).Select
Selection.Cut
Columns(\"C:C\"«»).Select
Selection.Insert Shift:=xlToRight
Columns(\"E:E\"«»).Select
Selection.NumberFormat = \"#,##0.00 $\"
Range(\"F2\"«»).Select
ActiveCell.FormulaR1C1 = \"1\"
Range(\"F2\"«»).Select
Selection.Copy
Columns(\"E:E\"«»).Select
Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlMultiply, _
SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
Range(\"F2\"«»).Select
Selection.ClearContents
Columns(\"E:E\"«»).Select
Selection.TextToColumns Destination:=Range(\"E:E\"«»), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
:=Array(1, 1), TrailingMinusNumbers:=True
Columns(\"E:E\"«»).Select
Selection.NumberFormat = \"#,##0.00 $\"
Range(\"A1\"«»).Select
ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:= _
\"lots!R1C1:R560C5\"«»).CreatePivotTable TableDestination:=\"\", TableName:= _
\"Tableau croisé dynamique2\", DefaultVersion:=xlPivotTableVersion10
ActiveSheet.PivotTableWizard TableDestination:=ActiveSheet.Cells(3, 1)
ActiveSheet.Cells(3, 1).Select
ActiveSheet.PivotTables(\"Tableau croisé dynamique2\"«»).AddFields RowFields:= _
Array(\"CODE CAT\", \"DESIGNATION\", \"LOT\", \"LIG\"«»)
ActiveSheet.PivotTables(\"Tableau croisé dynamique2\"«»).PivotFields(\"NET TTC\"«»). _
Orientation = xlDataField
Columns(\"A:E\"«»).Select
Columns(\"A:E\"«»).EntireColumn.AutoFit
Range(\"A11\"«»).Select
ActiveSheet.PivotTables(\"Tableau croisé dynamique2\"«»).PivotSelect _
\"DESIGNATION[All;Total]\", xlDataAndLabel, True
Selection.Delete
Columns(\"E:E\"«»).Select
Selection.NumberFormat = \"#,##0.00 $\"
ActiveSheet.PivotTables(\"Tableau croisé dynamique2\"«»).PivotSelect _
\"'CODE CAT'[All;Total]\", xlDataAndLabel, True
ActiveSheet.PivotTables(\"Tableau croisé dynamique2\"«»).PivotFields(\"CODE CAT\"«»). _
AutoSort xlDescending, \"Somme de NET TTC\"
With Selection.Interior
.ColorIndex = 37
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
End With
Range(\"A1\"«»).Select

End Sub
[/code:1]

Merci à vous pour votre aide.

Cordialement.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 7 mois #5125 par Laurent Dardenne
Salut,
bon déjà tu nous donnes des specs détaillées :lol:

Eric_K écrit:

comment fait-on pour scinder des lignes d'un script pour éviter d'avoir des lignes qui font des Kms de long.

Si c'est un pipe, tu peux placer un retour chariot après le pipe, PS recherche automatiquement la suite sur la ligne suivante ( dans d'autre cas la virgule provoque le même comportement).
Ou utiliser le backtick ( Alt-Gr 7 sur un clavier Fr)
Pour la première ligne du 1er exemple :
[code:1]
(Get-Content lot1.txt) |
Where-Object {$_ -notmatch \"PROPO DE PRIX\"} |
Where-Object {$_ -notmatch \"Tty :\"} |
Where-Object {$_ -notmatch \"User :\"} |
Where-Object {$_ -notmatch \"TOTAL HORS TAXES NET\"} |
Where-Object {$_ -notmatch \"- TVA\"} |
Foreach-Object {$_ -replace \"\++ \+\|\ \", \"\"} |
Foreach-Object {$_ -replace \"\ \|\", \";\"} |
Foreach-Object {$_ -replace \"\|\", \";\"} |
Foreach-Object {$_ -replace \";\ \", \";\"} |
Foreach-Object {$_ -replace \"12D \", \"\"} |
Foreach-Object {$_ -replace \"\", \"\"} |
Foreach-Object {$_ -replace \";LIG;CODE CAT;DESIGNATION;PU NET TTC;\", \"\"} |
Foreach-Object {$_ -replace \";LIG;CODE CAT;DESIGNATION;NET TTC;\", \"\"} |
where {$_ -ne \"\"} |
Set-Content lot1.txt
[/code:1]
Ensuite on peut essayer de regrouper certains segment dans une seule expression régulière :
[code:1]
\"PROPO DE PRIX\",\"Tty :\",\"User :\",\"TOTAL HORS TAXES NET\",\"Dernier OK\",\"Un User Tty:\",\"Un User Tty :\",\"user\"|
Where-Object {$_ -notmatch \"(PROPO DE PRIX|Tty :|User :|TOTAL HORS TAXES NET)\" }
[/code:1]
A tester, les segments de pipe manque un peut de commentaire...

Eric_K écrit:

Mais je voudrais pouvoir le faire par boucle sur l'ensemble des fichiers lotXX.txt d'un répertoire sans en connaître le nombre.

Soit un
[code:1]
Dir lot*.txt|Gc| Where-Object {$_ -notmatch ...
[/code:1]
Mais pour le dernier segment on a besoin de mémoriser le nom de fichier puis de le réemettre :
[code:1]
Dir lot*.txt|% {$CurrentFilename=$_.FullName;$_}|Gc|% {Write-Host \"Fichier $CurrentFilename traité.\"}
[/code:1]
Eric_K écrit:

- pour chaque fichier lotXX.txt : que sur la première colonne du fichier et sur chaque ligne du fichier apparaisse le nombre représenté par les XX du nom du fichier suivi d'un point virgule.
(Je n'ai pas réussi à trouver comment faire pour effectuer cette manipulation)

Todo :-)<br><br>Message édité par: Laurent Dardenne, à: 19/08/09 17:13

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 7 mois #5128 par Eric_K
Merci Laurent pour ton aide, mais je n'obtiens pas exactement ce que je souhaiterais.
Car les sorties du gc se font dans la console et ne sont pas réécrites dans chaque fichier.

Mon fichier de départ lotXX.txt se présente sous cette forme :

12D


| PROPO DE PRIX - TTC - 0000002303 DATE:05/08/2009 |
| User : nom HEURE: 14:59:37 |
| Tty : pts/84 LOT : 3 - LOT 2 FOLIO: 1 |

|LIG| CODE CAT | DESIGNATION |PU NET TTC|
++ +|
| 1| 00199/01 |ARTICLE 1 | 0.42|
++ +|
| 2| 00015 |ARTICLE 2 | 1.16|
++ +|
| 3| 01178 |ARTICLE 3 | 5.56|
++ +|
| 4| 01845 |ARTICLE 4 | 5.97|
++ +|
| 5| 00203/01 |ARTICLE 5 | 0.90|
++ +|
| 6| 00203/06 |ARTICLE 6 | 0.90|
++ +|
| 7| 00016 |ARTICLE 7 | 0.19|
++ +|
| 8| 00016 |ARTICLE 7 | 0.19|
++ +|
| 9| 00015 |ARTICLE 2 | 1.16|
++ +|
| 10| 00001 |ARTICLE 8 | 0.16|
++ +|


Après exécution du code :
[code:1]
Dir lotXX.txt| gc | Where-Object {$_ -notmatch \&quot;(PROPO DE PRIX|Tty :|User :|TOTAL HORS TAXES NET|TVA)\&quot; } |
Foreach-Object {$_ -replace \&quot;\++ \+\|\ \&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;\ \|\&quot;, \&quot;;\&quot;} |
Foreach-Object {$_ -replace \&quot;\|\&quot;, \&quot;;\&quot;} |
Foreach-Object {$_ -replace \&quot;;\ \&quot;, \&quot;;\&quot;} |
Foreach-Object {$_ -replace \&quot;12D \&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;\&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;;LIG;CODE CAT;DESIGNATION;PU NET TTC;\&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;;LIG;CODE CAT;DESIGNATION;NET TTC;\&quot;, \&quot;\&quot;} |
where {$_ -ne \&quot;\&quot;} |
Set-Content lotXX.txt
[/code:1]

Il devient :

;1;00199/01;ARTICLE 1;0.42;
;2;00015;ARTICLE 2;1.16;
;3;01178;ARTICLE 3;5.56;
;4;01845;ARTICLE 4;5.97;
;5;00203/01;ARTICLE 5;0.90;
;6;00203/06;ARTICLE 6;0.90;
;7;00016;ARTICLE 7;0.19;
;8;00016;ARTICLE 7;0.19;
;9;00015;ARTICLE 2;1.16;
;10;00001;ARTICLE 8;0.16;


Jusque là tout va bien avec les modifications que j'ai faites suivant tes remarques pour regrouper certains segments dans une seule expression régulière.

(Where-Object {$_ -notmatch.......

Je n'ai cependant par réussi à faire la même chose avec les segments

Foreach-Object {$_ -replace .......

Mais peu importe.

Je n'ai pas encore trouvé comment ajouter le XX du nom de fichier (lotXX.txt) sur chaque ligne du fichier pour qu'il devienne (pour lot1.txt par exemple) :

1;1;00199/01;ARTICLE 1;0.42;
1;2;00015;ARTICLE 2;1.16;
1;3;01178;ARTICLE 3;5.56;
1;4;01845;ARTICLE 4;5.97;
1;5;00203/01;ARTICLE 5;0.90;
1;6;00203/06;ARTICLE 6;0.90;
1;7;00016;ARTICLE 7;0.19;
1;8;00016;ARTICLE 7;0.19;
1;9;00015;ARTICLE 2;1.16;
1;10;00001;ARTICLE 8;0.16;


pour lot2.txt :

2;1;00199/01;ARTICLE 1;0.42;
2;2;00015;ARTICLE 2;1.16;
2;3;01178;ARTICLE 3;5.56;
2;4;01845;ARTICLE 4;5.97;
2;5;00203/01;ARTICLE 5;0.90;
2;6;00203/06;ARTICLE 6;0.90;
2;7;00016;ARTICLE 7;0.19;
2;8;00016;ARTICLE 7;0.19;
2;9;00015;ARTICLE 2;1.16;
2;10;00001;ARTICLE 8;0.16;


etc.....

Si j'ai 20 fichiers de lot1.txt à lot20.txt le fichier final après concaténation avec le fichier entête.txt et avant transformation en csv devrait ressembler à ça :

LOT;LIG;CODE CAT;DESIGNATION;NET TTC
1;1;00199/01;ARTICLE 1;0.42;
1;2;00015;ARTICLE 2;1.16;
1;3;01178;ARTICLE 3;5.56;
1;4;01845;ARTICLE 4;5.97;
1;5;00203/01;ARTICLE 5;0.90;
1;6;00203/06;ARTICLE 6;0.90;
1;7;00016;ARTICLE 7;0.19;
1;8;00016;ARTICLE 7;0.19;
1;9;00015;ARTICLE 2;1.16;
1;10;00001;ARTICLE 8;0.16;
2;1;00199/01;ARTICLE 1;0.42;
2;2;00015;ARTICLE 2;1.16;
2;3;01178;ARTICLE 3;5.56;
2;4;01845;ARTICLE 4;5.97;
2;5;00203/01;ARTICLE 5;0.90;
2;6;00203/06;ARTICLE 6;0.90;
2;7;00016;ARTICLE 7;0.19;
2;8;00016;ARTICLE 7;0.19;
2;9;00015;ARTICLE 2;1.16;
2;10;00001;ARTICLE 8;0.16;
..........
20;1;00199/01;ARTICLE 1;0.42;
20;2;00015;ARTICLE 2;1.16;
20;3;01178;ARTICLE 3;5.56;
20;4;01845;ARTICLE 4;5.97;
20;5;00203/01;ARTICLE 5;0.90;
20;6;00203/06;ARTICLE 6;0.90;
20;7;00016;ARTICLE 7;0.19;
20;8;00016;ARTICLE 7;0.19;
20;9;00015;ARTICLE 2;1.16;
20;10;00001;ARTICLE 8;0.16;


Actuellement, j'ajoute manuellement le XX sur chaque ligne de chaque fichier. Quand il y en a 1 ou 2 ça va mais quand il y en a plus ça fait long.

Dans tes remarques, je n'ai pas compris à quoi servait :

Mais pour le dernier segment on a besoin de mémoriser le nom de fichier puis de le réemettre :

[code:1]
Dir lot*.txt|% {$CurrentFilename=$_.FullName;$_}|Gc|% {Write-Host \&quot;Fichier $CurrentFilename traité.\&quot;}
[/code:1]

Ce code (Write-Host) me fait une sortie dans la console :

Fichier C:\test\lot1.txt traité.
Fichier C:\test\lot2.txt traité.


Je ne veux pas de sortie dans la console, je souhaiterais que toutes les modifications soient réécrites dans chacun des fichiers. Avec le code que tu m'as donné les modifications sont retranscrites dans la console mais pas dans les fichiers.
C'est pour ça qu'au départ j'avais pensé faire une boucle qui m'effectue une modification sur chaque fichier et qui me réécrive chaque fichier avant concaténation. Un code du style :
[code:1]
ForEach ($elements in $collection) Do | Where-Object {$_ -notmatch....... | Foreach-Object {$_ -replace..... |Set-Content lotXX.txt
[/code:1]

Je sais que la syntaxe n'est pas correcte, puisque j'ai essayé et ça ne fonctionne pas. C'est pour ça que je suis venu sur ce forum chercher un peu d'aide.

Merci encore à vous.

Cordialement.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 7 mois #5132 par Laurent Dardenne
Eric_K écrit:

Je n'ai cependant par réussi à faire la même chose avec les segments (replace)

Pour les remplacements à l'aide de regex je ne pense pas que cela soit possible.
Mais sur une string on peut utiliser plusieurs appel à replace, cette méthode renvoi une chaîne :
[code:1]
#attention à la casse
$s=\&quot;Test Ok\&quot;
$S.Replace(\&quot;Test\&quot;,\&quot;1\&quot;«»).Replace(\&quot;Ok\&quot;,\&quot;2\&quot;«»)
$S
[/code:1]
Reste à voir si cela est plus efficace...
Eric_K écrit:

Dans tes remarques, je n'ai pas compris à quoi servait :

Mais pour le dernier segment on a besoin de mémoriser le nom de fichier puis de le réemettre :

Dir renvoi des objets de type fichier et Get-Content des objets de type String, on perd donc l'information d'origine, à savoir le nom de fichier.
C'est pour cette raison qu'on doit le mémoriser.
Eric_K écrit:

Je ne veux pas de sortie dans la console,

J'ai bien compris.
Eric_K écrit:

Avec le code que tu m'as donné les modifications sont retranscrites dans la console mais pas dans les fichiers.

Oui car c'est un exemple, que je pensais simplifié, pour t'énoncer l'idée. Donc insérer dans ton code cela donne :
[code:1]
Dir lot*.txt||% {$CurrentFilename=$_.FullName;$_}| Where-Object {$_ -notmatch....... | Foreach-Object {$_ -replace..... |Set-Content $CurrentFilename
[/code:1]
C'est plus mieux clair ?
A tester bien sur :-)
Eric_K écrit:

Je sais que la syntaxe n'est pas correcte

La syntaxe de ton pipeline est on ne peut plus correcte, mais sa construction ne répond pas à ton besoin.
IL s'agit à mon avis d'un pb de compréhension du fonctionnement du pipeline, les objets qui y transitent peuvent ne pas être du même type pendant le parcours des segments composant le pipeline.
[code:1]
#la virgule force l'envoi du tableau et
#évite l'énumération de ces éléments
,@(1,2,3)|
Foreach-Object {Write-host $_.getType();$_.Count}|
Foreach-Object {Write-host $_.getType();$_.getType().FullName}|
Foreach-Object {Write-host $_.getType()}
[/code:1]
On reçoit :

#un tableau @(1,2,3)
System.Object[]
#puis un entier tableau.count (3)
System.Int32
#Puis une chaîne de caractères,
#le nom du type de l'objet envoyé précédement dans le pipe
System.String

Eric_K écrit:

Je n'ai pas encore trouvé comment ajouter le XX du nom de fichier (lotXX.txt) sur chaque ligne du fichier...

Là tu as un nouveau besoin. Le chiffre doit être extrait du nom de fichier, mémorisé puis ajouté à chaque ligne que reçoit Set-Content, c'est à dire dans le segment le précédent ou en ajouter un dédié.
Si le dernier élément est une chaîne ceci devrait suffire
[code:1]
\&quot;$number;$_\&quot;
[/code:1]
qq chose comme
[code:1]
Dir lot*.txt||% {$CurrentFilename=$_.FullName;$NUMBER=EXTRAITNUMBER$_}|
Where-Object {$_ -notmatch....... |
Foreach-Object {$_ -replace..... |
where {$_ -ne \&quot;\&quot;} |
Foreach-Object {\&quot;$NUMBER;$_\&quot;}
Set-Content $CurrentFilename
[/code:1]
Pour l'extraction je ferais qq chose dans le genre :
[code:1]
\&quot;lot1.txt\&quot;,\&quot;lotissement.txt\&quot;,\&quot;lot.txt\&quot;,\&quot;Ilot2.txt\&quot;,\&quot;lot23.txt\&quot;,\&quot;lot2589.txt\&quot;,\&quot;1lot2.txt\&quot;,\&quot;lot98test.txt\&quot;|
Where {$_ -match \&quot;^lot([0-9]*).txt\&quot;}|
% {$Matches[1]}

\&quot;lot1.txt\&quot;,\&quot;lotissement.txt\&quot;,\&quot;lot.txt\&quot;,\&quot;Ilot2.txt\&quot;,\&quot;lot23.txt\&quot;,\&quot;lot2589.txt\&quot;,\&quot;1lot2.txt\&quot;,\&quot;lot98test.txt\&quot;|
Where {$_ -match \&quot;^lot([0-9]+).txt\&quot;}|
% {$Matches[1]}
[/code:1]
Dans la regex le caractère étoile match \&quot;lot.txt\&quot; mais pas avec le caractère plus
Je te laisse étudier ça.<br><br>Message édité par: Laurent Dardenne, à: 20/08/09 12:27

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 7 mois #5140 par Eric_K
Bonjour Laurent,

Bon, plus ça va moins ça va.
Plus rien ne fonctionne.

Explications :

Le code :
[code:1]
Dir lot*.txt||% {$CurrentFilename=$_.FullName;$NUMBER=EXTRAITNUMBER$_}
[/code:1]

me renvoie l'erreur :

Le jeton « || » n'est pas un séparateur d'instructions valide dans cette version.
Au niveau de ligne : 1 Caractère : 15
+ Dir lot*.txt||% &lt;&lt;&lt;&lt; {$CurrentFilename=$_.FullName;$NUMBER=EXTRAITNUMBER$_}


J'ai donc supprimé un \&quot;|\&quot; mais j'ai cette erreur :

Le terme « EXTRAITNUMBER$_ » n'est pas reconnu en tant qu'applet de commande, fonction, programme exécutable ou fichier
de script. Vérifiez le terme et réessayez.
Au niveau de ligne : 1 Caractère : 69


Débutant vraiment en Powershell et en script, tout court, je n'arrive pas me sortir de cette erreur.

J'ai fait quelques recherches sur internet et j'ai trouvé ce code :
[code:1]
[IO.Path]::GetFileNameWithoutExtension($_)
[/code:1]
qui me permet de récupérer le nom de fichier sans l'extension. J'ai donc transformé ton code en :
[code:1]
Dir lot*.txt | % {$CurrentFilename=$_.FullName;$NUMBER=[IO.Path]::GetFileNameWithoutExtension($_)}
[/code:1]
et cette fois je n'ai pas d'erreur.
J'ai bien mes variables $currentfilename et $number qui sont correctement renseignées :

PS C:\test&gt; write-host $currentfilename
C:\test\lot2.txt
PS C:\test&gt; write-host $number
lot2

Je continue donc avec ton code :
[code:1]
Foreach-Object {\&quot;$NUMBER;$_\&quot;} |
Set-Content $CurrentFilename
[/code:1]
et là, rien ne se passe. Je veux dire que le contenu de la variable $number n'est pas écrite sur chaque ligne de chacun de mes fichiers. Le contenu de chacun des fichiers est inchangé.

Pour éviter d'autres erreurs générées par d'autres lignes du script, j'ai créé un nouveau script ne contenant que ces lignes là :
[code:1]
Dir lot*.txt | % {$CurrentFilename=$_.FullName;$NUMBER=[IO.Path]::GetFileNameWithoutExtension($_)}|
Foreach-Object {\&quot;$NUMBER;$_\&quot;} |
Set-Content $CurrentFilename
[/code:1]

Pour ce qui est de l'extraction du nom de fichier, je n'ai pas besoin de vérifier la syntaxe ou la longueur de celui-ci car les noms de fichiers seront tous du type lot1.txt .... lot30.txt. Je peux donc juste prendre le nom du fichier sans son extension (GetFileNameWithoutExtension) sans que ça me pose de problème par la suite.

Merci encore pour tout.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 7 mois #5144 par Laurent Dardenne
Eric_K écrit:

Bon, plus ça va moins ça va.

On a un peu de mal à se comprendre.
De mon coté j'aurais du préciser que EXTRAITNUMBER ce voulait être un code d'extraction, et pas un appel de code existant...
Eric_K écrit:

Pour ce qui est de l'extraction du nom de fichier, je n'ai pas besoin de vérifier la syntaxe ou la longueur de celui-ci car les noms de fichiers seront tous du type lot1.txt .... lot30.txt. Je peux donc juste prendre le nom du fichier sans son extension (GetFileNameWithoutExtension) sans que ça me pose de problème par la suite.

Utile précision.

Le second segment du pipeline, celui où tu extrais le nom de fichier suivant, ne renvoi rien
[code:1]
Dir lot*.txt | % {$CurrentFilename=$_.FullName;$NUMBER=[IO.Path]::GetFileNameWithoutExtension($_)}|
Foreach-Object {\&quot;$NUMBER;$_\&quot;} |
Set-Content $CurrentFilename
[/code:1]
Dans ton code d'origine l'opérateur -Replace renvoi un résultat,en revanche celui-ci ne contient que des affectations :
[code:1]
{$CurrentFilename=$_.FullName;$NUMBER=[IO.Path]::GetFileNameWithoutExtension($_)}
[/code:1]
tu dois donc dans ce cas réémettre l'objet que tu as reçu, objet qui t'as permit d'extraire et de mémoriser le nom.
Le cmdlet Foreach-object effectue un traitement sur un objet reçu mais c'est à toi de t'assurer qu'il, le cmdlet, renvoi qq chose au segment suivant.
Il faut lui ajouter l'envoi de l'objet reçu ( $_) dans le pipeline puisque le segment suivant l'utilise,
[code:1]
{$CurrentFilename=$_.FullName;$NUMBER=[IO.Path]::GetFileNameWithoutExtension($_);$_}
[/code:1]
La position importe peut:
[code:1]
{$_;$CurrentFilename=$_.FullName;$NUMBER=[IO.Path]::GetFileNameWithoutExtension($_)}
{$CurrentFilename=$_.FullName;$_;$NUMBER=[IO.Path]::GetFileNameWithoutExtension($_)}
[/code:1]
De le placer en dernier facilite la relecture.

Pour le segment suivant
[code:1]
Foreach-Object {\&quot;$NUMBER;$_\&quot;}
[/code:1]
par défaut sous PowerShell le résultat d'une commande/instruction est envoyé dans le pipe, s'il n'en existe pas on l'envoi sur la console.
Dans ce cas tu envois bien un résultat dans le pipe, une chaîne.

Ce qui nous donne :
[code:1]
Dir lot*.txt|
Foreach-Object {$CurrentFilename=$_.FullName;$FName=[IO.Path]::GetFileNameWithoutExtension($_);$_}|
Get-Content |
Where-Object {$_ -notmatch \&quot;(PROPO DE PRIX|Tty :|User :|TOTAL HORS TAXES NET|TVA)\&quot; } |
Foreach-Object {$_ -replace \&quot;\++ \+\|\ \&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;\ \|\&quot;, \&quot;;\&quot;} |
Foreach-Object {$_ -replace \&quot;\|\&quot;, \&quot;;\&quot;} |
Foreach-Object {$_ -replace \&quot;;\ \&quot;, \&quot;;\&quot;} |
Foreach-Object {$_ -replace \&quot;12D \&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;\&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;;LIG;CODE CAT;DESIGNATION;PU NET TTC;\&quot;, \&quot;\&quot;} |
Foreach-Object {$_ -replace \&quot;;LIG;CODE CAT;DESIGNATION;NET TTC;\&quot;, \&quot;\&quot;} |
where {$_ -ne \&quot;\&quot;} |
Foreach-Object {\&quot;$FName;$_\&quot;} |
Set-Content $CurrentFilename
[/code:1]
A tester ;)<br><br>Message édité par: Laurent Dardenne, à: 21/08/09 11:00

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.086 secondes
Propulsé par Kunena