Join columns from different txt files - powershell - powershell

I need to extract columns from one file and join them in another file.
I used this code to select the columns that I need:
$original_path = 'C:\Users\leticia.araujo\Downloads\Arquivo Buffer\Arquivo teste'
$files = Get-ChildItem $original_path
ForEach($file in $files) {
$pathFile = $original_path + '\' + $file.Name
$SegundaColuna = Get-Content -Path $pathFile | Foreach {"$(($_ -split ',')[3..3])"}
$TerceiraColuna = Get-Content -Path $pathFile | Foreach {"$(($_ -split ':')[3..3])"}
$QuartaColuna = Get-Content -Path $pathFile | Foreach {"$(($_ -split ',')[10..10])"}
}
When I try to put these in a txt using
'Add-Content $pathFile $SegundaColuna,$TerceiraColuna,$QuartaColuna'
I got, but in the file the columns are not next to each other. they are under each other.
Example:
I need they are like this:
1 a
2 b
3 c
But they are like this:
1
2
3
a
b
c

Focusing on a single file inside your foreach loop:
Since the values to join come from the same lines of a given file, read that file line by line:
Get-Content -Path $pathFile | # Read the file line by line.
ForEach-Object { # Process each line.
($_ -split ',')[3],
($_ -split ':')[3],
($_ -split ',')[10] -join ' ' # Output the column values joined with a space.
} |
Set-Content out.txt
If you need to merge columns across all your input files and create a single output file, replace the foreach loop with a single pipeline:
Get-ChildItem $original_path |
Get-Content |
ForEach-Object {
($_ -split ',')[3],
($_ -split ':')[3],
($_ -split ',')[10] -join ' '
} |
Set-Content out.txt

Related

powershell replace $_ if criteria meets

I read a xml file and want to replace three strings.
My Code:
foreach ($file in Get-ChildItem $files){
(Get-Content $file) | Foreach-Object {
$_ -replace 'TABLE_NAME="\$ZoneProdukt\$', ('TABLE_NAME="' + $ZONPRODLANG)`
-replace 'OPTION="Copy" ', '' `
-replace ('<JOB ','<JOB TIMETO="TEST" ') | ? {$_ -notlike "*TIMETO=`""}
} | Set-Content ($destination_folder + $file.name)
}
the last replace provides only the half of the result I
expect.
If there are lines containing "JOB" and "TIMETO" they will not be displayed (because of Where-Object)
How to keep lines if the mentioned "TIMETO"-Attribute already exists?
examples:
source line in file (without "TIMETO"):
<JOB JOBISN="30" USER="testuser">
correct replace:
<JOB TIMETO="TEST" JOB JOBISN="30" USER="testuser">
....
....
source line in file (with "TIMETO"):
<JOB JOBISN="30" USER="testuser" TIMETO="0400">
replace -> this line will not be displayed !!
..
thanks in advance! br danijel
You could use an if-statement in your ForEach-Object:
foreach ($file in Get-ChildItem $files){
(Get-Content $file) | Foreach-Object {
if($_ -like "*TIMETO=`""){
$_ -replace 'TABLE_NAME="\$ZoneProdukt\$', ('TABLE_NAME="' + $ZONPRODLANG)`
-replace 'OPTION="Copy" ', '' `
}else{
$_ -replace 'TABLE_NAME="\$ZoneProdukt\$', ('TABLE_NAME="' + $ZONPRODLANG)`
-replace 'OPTION="Copy" ', '' `
-replace ('<JOB ','<JOB TIMETO="TEST" ')
}
} | Set-Content ($destination_folder + $file.name)
}
Manipulating xml using regex is generally bad practice. You should use Get-Content and cast as [xml], which will allow you to manipulate the object. Check out this this MSDN demo.

Need to output multiple rows to CSV file

I am using the following script that iterates through hundreds of text files looking for specific instances of the regex expression within. I need to add a second data point to the array, which tells me the object the pattern matched in.
In the below script the [Regex]::Matches($str, $Pattern) | % { $_.Value } piece returns multiple rows per file, which cannot be easily output to a file.
What I would like to know is, how would I output a 2 column CSV file, one column with the file name (which should be $_.FullName), and one column with the regex results? The code of where I am at now is below.
$FolderPath = "C:\Test"
$Pattern = "(?i)(?<=\b^test\b)\s+(\w+)\S+"
$Lines = #()
Get-ChildItem -Recurse $FolderPath -File | ForEach-Object {
$_.FullName
$str = Get-Content $_.FullName
$Lines += [Regex]::Matches($str, $Pattern) |
% { $_.Value } |
Sort-Object |
Get-Unique
}
$Lines = $Lines.Trim().ToUpper() -replace '[\r\n]+', ' ' -replace ";", '' |
Sort-Object |
Get-Unique # Cleaning up data in array
I can think of two ways but the simplest way is to use a hashtable (dict). Another way is create psobjects to fill your Lines variable. I am going to go with the simple way so you can only use one variable, the hashtable.
$FolderPath = "C:\Test"
$Pattern = "(?i)(?<=\b^test\b)\s+(\w+)\S+"
$Results =#{}
Get-ChildItem -Recurse $FolderPath -File |
ForEach-Object {
$str = Get-Content $_.FullName
$Line = [regex]::matches($str,$Pattern) | % { $_.Value } | Sort-Object | Get-Unique
$Line = $Line.Trim().ToUpper() -Replace '[\r\n]+', ' ' -Replace ";",'' | Sort-Object | Get-Unique # Cleaning up data in array
$Results[$_.FullName] = $Line
}
$Results.GetEnumerator() | Select #{L="Folder";E={$_.Key}}, #{L="Matches";E={$_.Value}} | Export-Csv -NoType -Path <Path to save CSV>
Your results will be in $Results. $Result.keys contain the folder names. $Results.Values has the results from expression. You can reference the results of a particular folder by its key $Results["Folder path"]. of course it will error if the key does not exist.

Convert 2 columns file into 1 column

I have a text file with 2 columns and any number of lines (100 or more):
data1 data2
data3 data4
I want to transform it to 1 column like this:
data1
data2
data3
data4
In unix I could have done it with for loop and awk, but getting confused being very new to PowerShell.
# Read lines, loop each line with the variable name $_
Get-Content c:\wherever\input.txt | ForEach-Object {
-split $_ # unary split breaks on whitespace
# pieces go down the pipeline
} | Set-Content c:\wherever\output.txt -Encoding UTF8 # save them to a file
or in the shell, for brevity:
-split(gc 1.txt)|sc 2.txt -En utf8
#Solution 1, get data with delimiter and remove blanck line and carriage return
get-content "C:\temp\test\test1.txt" -delimiter " " | where {$_ -ne " "} | foreach {$_ -replace "`n", ""}
#Solution 2, import-csv with delimiter and print 2 columns C1 and C2
import-csv "C:\temp\test\test1.txt" -Delimiter " " -Header C1, C2 | foreach {$_.C1;$_.C2}
#Solution 3, variante of solution 2
get-content "C:\temp\test\test1.txt" | ConvertFrom-Csv -Delimiter " " -Header C1, C2 | %{$_.C1;$_.C2}
#Solution 4, variante of solution 3 but with convertfrom-string (autocomun P1 and P2 are builded)
get-content "C:\temp\test\test1.txt" | ConvertFrom-String -Delimiter " " | %{$_.P1;$_.P2}
#Solution 5 with split every row (proposed by TessellatingHeckler )
get-content "C:\temp\test\test1.txt" | foreach {-split $_ }
$textfile = "path/sourcefile" #path and name of the source text file
$newfile = 'newfile.txt' #name of the new text file
New-Item -ItemType file -Name $newfile #a new text file will be created from wherever you are running this script from if you have the script saved and named, else it will be created in the c drive.
$textfile = Get-Content $textfile #source text file being red and stored into a variable
foreach ($line in $textfile) {
$datas = $line.split(' ') | where { $_.length -gt 1 } #each line in the text file is being split and spaces being excluded
foreach ($data in $datas)
{ Add-Content $newfile $data } #columns being merged, this will work with multiple columns which are separated by a space

Filtering sections of data including the starting and ending lines- PowerShell

I have a text file that looks like this:
Data I'm NOT looking for
More data that doesn't matter
Even more data that I don't
&Start/Finally the data I'm looking for
&Data/More data that I need
&Stop/I need this too
&Start/Second batch of data I need
&Data/I need this too
&Stop/Okay now I'm done
Ending that I don't need
Here is what the output needs to be:
File1.txt
&Start/Finally the data I'm looking for
&Data/More data that I need
&Stop/I need this too
File2.txt
&Start/Second batch of data I need
&Data/I need this too
&Stop/Okay now I'm done
I need to do this for every file in a folder (sometimes there will be multiple files that will need to be filtered.) The files names can be incrementing: ex. File1.txt, File2.txt, File3.txt.
This is what I have tried with no luck:
ForEach-Object{
$text -join "`n" -split '(?ms)(?=^&START)' -match '^&START' |
Out-File B:\PowerShell\$filename}
Thanks!
Looks like you were pretty close: your code correctly extracted the paragraphs of interest, but intra-paragraph out-filtering of non-&-starting lines was missing, and you needed to write to paragraph-specific output files:
$text -join "`n" -split '(?m)(?=^&Start)' -match '^&Start' |
ForEach-Object { $ndx=0 } { $_ -split '\n' -match '^&' | Out-File "File$((++$ndx)).txt" }
This creates sequentially numbered files starting with File1.txt for every paragraph of interest.
To do it for every file in a folder, with output filenames using fixed naming scheme File<n> across all input files (and thus cumulative numbering):
Get-ChildItem -File . | ForEach-Object -Begin { $ndx=0 } -Process {
(Get-Content -Raw $_) -split '(?m)(?=^&Start)' -match '^&Start' |
ForEach-Object { $_ -split '\n' -match '^&' | Out-File "File$((++$ndx)).txt" }
}
To do it for every file in a folder, with output filenames based on the input filenames and numbering per input file (PSv4+, due to use of -PipelineVariable):
Get-ChildItem -File . -PipelineVariable File | ForEach-Object {
(Get-Content -Raw $_) -split '(?m)(?=^&Start)' -match '^&Start' |
ForEach-Object {$ndx=0} { $_ -split '\n' -match '^&' | Out-File "$($File.Name)$((++$ndx)).txt" }
}
You post a second question (against the rules) and it was deleted but here is my quick answer for it. I hope it will help you and give you more sense how PS works:
$InputFile = "C:\temp\test\New folder (3)\File1.txt"
# get file content
$a=Get-Content $InputFile
# loop for every line in range 2 to last but one
for ($i=1; $i -lt ($a.count-1); $i++)
{
#geting string part between & and / , and construct output file name
$OutFile = "$(Split-Path $InputFile)\$(($a[$i] -split '/')[0] -replace '&','').txt"
$a[0]| Out-File $OutFile #creating output file and write first line in it
$a[$i]| Out-File $OutFile -Append #write info line
$a[-1]| Out-File $OutFile -Append #write last line
}
Something like this?
$i=0
gci -path "C:\temp\ExplodeDir" -file | %{ (get-content -path $_.FullName -Raw).Replace("`r`n`r`n", ";").Replace("`r`n", "~").Split(";") | %{if ($_ -like "*Start*") {$i++; ($_ -split "~") | out-file "C:\temp\ResultFile\File$i.txt" }} }

Retrieve text from a file in ps script

I have a text file containing some data as follows:
test|wdthe$muce
check|muce6um#%
How can I check for a particular string like test and retrieve the text after the | symbol to a variable in a PowerShell script?
And also,
If Suppose there is variable $from=test#abc.com and how to search the file by splitting the text before "#" ?
this may be one possible solution
$filecontents = #'
test|wdthe$muce
check|muce6um#%
'#.split("`n")
# instead of the above, you would use this with the path of the file
# $filecontents = get-content 'c:\temp\file.txt'
$hash = #{}
$filecontents | ? {$_ -notmatch '^(?:\s+)?$'} | % {
$split = $_.Split('|')
$hash.Add($split[0], $split[1])
}
$result = [pscustomobject]$hash
$result
# and to get just what is inside 'test'
$result.test
*note: this may only work if there is only one of each line in the file. if you get an error, try this other method
$search = 'test'
$filecontents | ? {$_ -match "^$search\|"} | % {
$_.split('|')[1]
}
First you need to read the text from the file.
$content = Get-Content "c:\temp\myfile.txt"
Then you want to grab the post-pipe portion of each matching line.
$postPipePortion = $content | Foreach-Object {$_.Substring($_.IndexOf("|") + 1)}
And because it's PowerShell you could also daisy-chain it together instead of using variables:
Get-Content "C:\temp\myfile.txt" | Foreach-Object {$_.Substring($_.IndexOf("|") + 1)}
The above assumes that you happen to know every line will include a | character. If this is not the case, you need to select out only the lines that do have the character, like this:
Get-Content "C:\temp\myfile.txt" | Select-String "|" | Foreach-Object {$_.Line.Substring($_.Line.IndexOf("|") + 1)}
(You need to use the $_.Line instead of just $_ now because Select-String returns MatchInfo objects rather than strings.)
Hope that helps. Good luck.
gc input.txt |? {$_ -match '^test'} |% { $_.split('|') | select -Index 1 }
or
sls '^test' -Path input.txt |% { $_.Line.Split('|') | select -Index 1 }
or
sls '^test' input.txt |% { $_ -split '\|' | select -Ind 1 }
or
(gc input.txt).Where{$_ -match '^test'} -replace '.*\|'
or
# Borrowing #Anthony Stringer's answer shape, but different
# code, and guessing names for what you're doing:
$users = #{}
Get-Content .\input.txt | ForEach {
if ($_ -match "(?<user>.*)\|(?<pwd>.*)") {
$users[$matches.user]=$matches.pwd
}
}
$users = [pscustomobject]$users