Foreach command ,initiation error - foreach

This is the list i have
set session_list [list ../../TIMING_ANALYSIS_CRPR/FUNC_ss28_0.85V_0.95V_0.85V_125C_RCmax/reports.15_03_10-22/SAVED_SESSION
../../TIMING_ANALYSIS_CRPR/FUNC_ff28_0.85V_0.95V_0.85V_m40C_Cmin/reports.15_03_10-22/SAVED_SESSION]
foreach j $session_list {
set x [string trimleft $j "../../TIMING_ANALYSIS_CRPR/ "]
}
foreach item $x {
puts "create_scenario -name $item "
}
so what i want is my output to the list be given out as :
create_scenario -name FUNC_ss28_0.85V_0.95V_0.85V_125C_RCmax/reports.15_03_10-22/SAVED_SESSION
create_scenario -name FUNC_ff28_0.85V_0.95V_0.85V_m40C_Cmin/reports.15_03_10-22/SAVED_SESSION
IN the top stated code ,it does not read the first foreach command and does not display the whole list

You are setting the value of x in each loop which will cause the x value to get overwritten.
You have to use lappend command
foreach j $session_list {
lappend x [string trimleft $j "../../TIMING_ANALYSIS_CRPR/ "]
}
foreach item $x {
puts "create_scenario -name $item "
}
Output :
create_scenario -name FUNC_ss28_0.85V_0.95V_0.85V_125C_RCmax/reports.15_03_10-22/SAVED_SESSION
create_scenario -name FUNC_ff28_0.85V_0.95V_0.85V_m40C_Cmin/reports.15_03_10-22/SAVED_SESSION
Reference : lappend

[string trimleft] doesn't do what you think it does. The line:
string trimleft $j "../../TIMING_ANALYSIS_CRPR/ "
basically means: remove the characters . and / and T and I and M and N and G and _ and A and N and L and Y and S and C and R and P and (single space) form the left of the string.
What you want instead is regsub:
regsub {^../../TIMING_ANALYSIS_CRPR/} $j ""

Related

Split EDI X12 files using Powershell

I am likely recreating the wheel here but this is my stab and solving an issue partly and asking for community assistance to resolve the remaining.
My task is to split EDI X12 documents into their own file (ISA to IEA)
and CRLF each line separately (similar to ex. EDI2.EDI below).
Below is my Powershell script and example EDI documents 1, 2 and 3.
My script will successfully split a contiguous X12 EDI document from ISA to IEA and CRLF into a file so that one contiguous string becomes something more readable. This works well and will even handle any segment delimiter as well as any line delimiter.
My issue is dealing with non-contiguous documents (ex. EDI2) or combined (ex. EDI3). The source folder could have any of the formatted files shown below. If the file already contains the CRLF, then I just need to split it from ISA to IEA. My script is failing when i pull in CRLF'd files.
Could someone help me solving this?
$sourceDir = "Z:\temp\EDI\temp\"
$targetDir = "Z:\temp\EDI\temp\archive"
<##### F U N C T I O N S #####>
<#############################>
Function FindNewFile
{
Param (
[Parameter(mandatory=$true)]
[string]$filename,
[int]$counter)
$filename = Resolve-Path $filename
$validFileName = "{0}\{1} {2}{3}" -f $targetDir, #([system.io.fileinfo]$filename).DirectoryName,
([system.io.fileinfo]$filename).basename,
$counter, #"1", #([guid]::newguid()).tostring("N"),
([system.io.fileinfo]$filename).extension
Return $validFileName
}
<###### M A I N L I N E ######>
<#############################>
If(test-path $sourceDir)
{
$files = #(Get-ChildItem $sourceDir | Where {!$_.PsIsContainer -and $_.extension -eq ".edi" -and $_.length -gt 0})
"{0} files to process. . ." -f $files.count
If($files)
{
If(!(test-path $targetDir))
{
New-Item $targetDir -ItemType Directory | Out-Null
}
foreach ($file in $files)
{
$me = $file.fullname
# Get the new file name
$isaCount = 1
$newFile = FindNewFile $me $isaCount
$data = get-content $me
# Reset variables for each new file
$dataLen = [int] $data.length
$linDelim = $null
$textLine = $null
$firstRun = $True
$errorFlag = $False
for($x=0; $x -lt $data.length; $x++)
{
$textLine = $data.substring($x, $dataLen)
$findISA = "ISA{0}" -f $textLine.substring(3,1)
If($textLine.substring(0,4) -eq $findISA)
{
$linDelim = $textLine.substring(105, 1)
If(!($FirstRun))
{
$isaCount++
$newFile = FindNewFile $me $isaCount
}
$FirstRun = $False
}
If($linDelim)
{
$delimI = $textLine.IndexOf($linDelim) + 1
$textLine = $textLine.substring(0,$delimI)
$fLine = $textLine
add-content $newFile $fLine
$x += $fLine.length - 1
$dataLen = $data.length - ($x + 1)
}
Else
{
$errorFlag = $True
"`t=====> {0} is not a valid EDI X12 file!" -f $me
$x += $data.length
}
}
If(!($errorFlag))
{
"{0} contained {1} ISA's" -f $me, $isaCount
}
}
}
Else
{
"No files in {0}." -f $sourceDir
}
}
Else
{
"{0} does not exist!" -f $sourceDir
}
Filename: EDI1.EDI
ISA*00* *00* *08*925xxxxxx0 *01*78xxxx100 *170331*1630*U*00401*000000114*0*P*>~GS*FA*8473293489*782702100*20170331*1630*42*T*004010UCS~ST*997*116303723~SE*6*116303723~GE*1*42~IEA*1*000000114~ISA*00* *00* *08*WARxxxxxx *01*78xxxxxx0 *170331*1545*U*00401*000002408*0*T*>~GS*FA*5035816100*782702100*20170331*1545*1331*T*004010UCS~ST*997*000001331~~SE*24*000001331~GE*1*1331~IEA*1*000002408~
Filename: EDI2.EDI
ISA*00* *00* *ZZ*REINxxxxxxxDSER*01*78xxxx100 *170404*0819*|*00501*100000097*0*P*}~
GS*PO*REINHxxxxxxDSER*782702100*20170404*0819*1097*X*005010~
ST*850*1097~
SE*14*1097~
GE*1*1097~
IEA*1*100000097~
Filename: EDI3.EDI
ISA*00* *00* *08*925xxxxxx0 *01*78xxxx100 *170331*1630*U*00401*000000114*0*P*>~GS*FA*8473293489*782702100*20170331*1630*42*T*004010UCS~ST*997*116303723~SE*6*116303723~GE*1*42~IEA*1*000000114~ISA*00* *00* *08*WARxxxxxx *01*78xxxxxx0 *170331*1545*U*00401*000002408*0*T*>~GS*FA*5035816100*782702100*20170331*1545*1331*T*004010UCS~ST*997*000001331~~SE*24*000001331~GE*1*1331~IEA*1*000002408~
ISA*00* *00* *ZZ*REINxxxxxxxDSER*01*78xxxx100 *170404*0819*|*00501*100000097*0*P*}~
GS*PO*REINHxxxxxxDSER*78xxxxxx0*20170404*0819*1097*X*005010~
ST*850*1097~
SE*14*1097~
GE*1*1097~
IEA*1*100000097~
FWIW, I've compiled this code from all over the net including stackoverflow.com. If you see your code and desire recognition, let me know and I'll add it. I'm not claiming any of this is original! My motto is "ARRRGH!"
EDI3 is an invalid X12 document, each file should only contain one ISA segment with repeated envelopes if required.
The segment terminator should also be consistent. In EDI3 it is both ~ and ~ which is again invalid.
Segment terminator should be tilde "~".
It can be suffixed by: nothing, "\n" or, "\r\n", what is optional is the suffix for human reading. Some implementations might be more relaxed in terms of the X12 standard.
https://www.ibm.com/support/knowledgecenter/en/SS6V3G_5.3.1/com.ibm.help.gswformstutscreen.doc/GSW_EDI_Delimiters.html
https://docs.oracle.com/cd/E19398-01/820-1275/agdbj/index.html
https://support.microsoft.com/en-sg/help/2723596/biztalk-2010-configuring-segment-terminator-for-an-x12-encoded-interch
BTW, check my splitter/viewer: https://gist.github.com/ppazos/94a63ab18910ab0c0d23c9ff4ff7e5c2

tcl loop through multiple lists

I have two lists I'd like manipulate.. ( I am a tcl newbie..). I'd like to associate these two lists and create a third list with some data added.
The data I have:
set aes {ae0 ae3 ae6 ae1v1 ae1v8}
set c {c1 c2 c3 k1 k2}
foreach A $aes {
foreach C $c {
puts ${A}_$C
}
}
The data I get as you'd expect is:
ae0_c1
ae0_c2
ae0_c3
ae0_k1
ae0_k2
..
..
What I want to do is
append some data in front of this.
AE-To-c = All ae0_c1 ae0_c2 ae0_c3 ae0_k1 ae0_k2 .. End.
% set aes {ae0 ae3 ae6 ae1v1 ae1v8}
ae0 ae3 ae6 ae1v1 ae1v8
% set c {c1 c2 c3 k1 k2}
c1 c2 c3 k1 k2
% foreach A $aes {
foreach C $c {
# saving into 'result' variable
lappend result ${A}_${C}
}
}
% set data "some more here"
some more here
% set result
ae0_c1 ae0_c2 ae0_c3 ae0_k1 ae0_k2 ae3_c1 ae3_c2 ae3_c3 ae3_k1 ae3_k2 ae6_c1 ae6_c2 ae6_c3 ae6_k1 ae6_k2 ae1v1_c1 ae1v1_c2 ae1v1_c3 ae1v1_k1 ae1v1_k2 ae1v8_c1 ae1v8_c2 ae1v8_c3 ae1v8_k1 ae1v8_k2
% set result [linsert $result 0 $data]
some more here ae0_c1 ae0_c2 ae0_c3 ae0_k1 ae0_k2 ae3_c1 ae3_c2 ae3_c3 ae3_k1 ae3_k2 ae6_c1 ae6_c2 ae6_c3 ae6_k1 ae6_k2 ae1v1_c1 ae1v1_c2 ae1v1_c3 ae1v1_k1 ae1v1_k2 ae1v8_c1 ae1v8_c2 ae1v8_c3 ae1v8_k1 ae1v8_k2
Your question isn't 100% clear. Is it something like this you want?
set res [list AE-To-c = All]
foreach A $aes {
foreach C $c {
lappend res ${A}_$C
}
}
lappend res End
If you want to do what I think you want to do, you need to capture the permutations of the two lists in a list instead of printing them out, and then wrap that list in a prefix and suffix.
The method above pre-loads the result list with the AE-To-c = All prefix, then picks up the permutations using lappend, and finally adds the End suffix as a last element in the list.
Another way:
set res [list]
foreach A $aes {
foreach C $c {
lappend res ${A}_$C
}
}
concat [list AE-To-c = All] $res End
In this variant the list of permutations is created first, and then the prefix list, the permutation list, and the suffix list (yes, End is a list) are concatenated into one flat list.
Documentation: concat, foreach, lappend, list, set

Parse and change the output of a system through Powershell

initially I have to state, that I have little to no experience with powershell so far. A previous system generates the wrong output for me. So I want to use PowerShell to change this. From the System I get an output looking like this:
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')^|^N^|^LIKE^|^('4','5','6','7')^|^...^|^Y^|^NOT IN^|^('8','9','10','11','12')
TEST2^|^9998^|^Y^|^NOT IN^|^('4','5','6')^|^N^|^LIKE^|^('6','7','8','9')^|^...^|^Y^|^NOT IN^|^('1','2','15','16','17')^|^Y^|^NOT IN^|^('18','19','20','21','22')
When you look at it, there is a starting part for each line (TEST1^|^9999^|^) followed by a1 to a-n tuples (example: Y^|^NOT IN^|^('1','2','3')^|^).
The way I want this to look like is here:
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')
TEST1^|^9999^|^N^|^LIKE^|^('4','5','6','7')
TEST1^|^9999^|^Y^|^NOT IN^|^('8','9','10','11','12')
TEST2^|^9998^|^Y^|^NOT IN^|^('4','5','6')
TEST2^|^9998^|^N^|^LIKE^|^('6','7','8','9')
TEST2^|^9998^|^Y^|^NOT IN^|^('1','2','15','16','17')
TEST2^|^9998^|^Y^|^NOT IN^|^('18','19','20','21','22')
So the tuples shall be printed out per line, with the starting part attached in front.
My solution approach is the AWK equivalent in Powershell, but to date I lack the understanding of how to tackle the issue of how to deal with an indetermined number of tuples and to repeat the starting block.
I thank you so much in advance for your help!
I'd split the lines at ^|^ and recombine the fields of the resulting array in a loop. Something like this:
$sp = '^|^'
Get-Content 'C:\path\to\input.txt' | % {
$a = $_ -split [regex]::Escape($sp)
for ($i=2; $i -lt $a.length; $i+=3) {
"{0}$sp{1}$sp{2}$sp{3}$sp{4}" -f $a[0,1,$i,($i+1),($i+2)]
}
} | Set-Content 'C:\path\to\output.txt'
The data looks quite regular so you could loop over it using | as the delimiter and counting the following cells in 3s:
$data = #"
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')^|^N^|^LIKE^|^('4','5','6','7')^|^Y^|^NOT IN^|^('8','9','10','11','12')
TEST2^|^9998^|^Y^|^NOT IN^|^('4','5','6')^|^N^|^LIKE^|^('6','7','8','9')^|^Y^|^NOT IN^|^('1','2','15','16','17')^|^Y^|^NOT IN^|^('18','19','20','21','22')
"#
$data.split("`n") | % {
$ds = $_.split("|")
$heading = "$($ds[0])|$($ds[1])"
$j = 0
for($i = 2; $i -lt $ds.length; $i += 1) {
$line += "|$($ds[$i])" -replace "\^(\((?:'\d+',?)+\))\^?",'$1'
$j += 1
if($j -eq 3) {
write-host $heading$line
$line = ""
$j = 0
}
}
}
Parsing an arbitary length string record to row records is quite error prone. A simple solution would be processing the data row-by-row and creating output.
Here is a simple illustration how to process a single row. Processing the whole input file and writing output is left as trivial an exercise to the reader.
$s = "TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')^|^N^|^LIKE^|^('4','5','6','7')^|^Y^|^NOT IN^|^('8','9','10','11','12')"
$t = $s.split('\)', [StringSplitOptions]::RemoveEmptyEntries)
$testNum = ([regex]::match($t[0], "(?i)(test\d+\^\|\^\d+)")).value # Hunt for 1st colum values
$t[0] = $t[0] + ')' # Fix split char remove
for($i=1;$i -lt $t.Length; ++$i) { $t[$i] = $testNum + $t[$i] + ')' } # Add 1st colum and split char remove
$t
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')
TEST1^|^9999^|^N^|^LIKE^|^('4','5','6','7')
TEST1^|^9999^|^Y^|^NOT IN^|^('8','9','10','11','12')

Why will Powershell write to the console, but not to a file?

I have a PowerShell script that sets flags based on various conditions of the file. I'll abbreviate for brevity.
$path = "c:\path"
$srcfiles = Get-ChildItem $path -filter *.htm*
ForEach ($doc in $srcfiles) {
$s = $doc.Fullname
Write-Host "Processing :" $doc.FullName
if (stuff) {flag 1 = 1} else {flag 1 = 0}
if (stuff) {flag 1 = 1} else {flag 1 = 0}
if (stuff) {flag 1 = 1} else {flag 1 = 0}
$t = "$s;$flag1;$flag2;$flag2"
Write-Host "Output: " $t
This all works great. My file processes, the flags are set properly, and a neat semicolon delimited line is generated as $t. However, if I slap these two lines at the end of the function,
$stream = [System.IO.StreamWriter] "flags.txt"
$stream.WriteLine $t
I get this error.
Unexpected token 't' in expression or statement.
At C:\CGC003a.ps1:53 char:25
+ $stream.WriteLine $t <<<<
+ CategoryInfo : ParserError: (t:String) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
If I'm reading this write, it appears that write-host flushed my variable $t before it got to the WriteLine. Before I try out-file, though, I want to understand what's happening to $t after Write-Host that prevents Write Line from seeing it as valid. Or is there something else I'm missing?
try:
$stream.WriteLine($t)
writeline is a method of streamwriter .net object. To pass in value you need to enclose it in ( )
-if you need to append to a streamwriter you need to create it like this:
$a = new-object 'System.IO.StreamWriter' -ArgumentList "c:\path\to\flags.txt",$true
Where the boolean arguments can be true to append data to the file orfalse to overwrite the file.
I suggest to pass full path for:
$stream = [System.IO.StreamWriter] "c:\path\to\flags.txt"
otherwise you create the file in .net current folder ( probably c:\windows\system32 if run as administrator your current powershell console, to know it type [System.IO.Directory]::GetCurrentDirectory())
you could try
$t > c:\path\to\flags.txt

parsing issue with comma separated csv file

I am trying to extract 4th column from csv file (comma separated, and skipping first 2 header lines) using this command,
awk 'NR <2 {next}{FS =","}{print $4}' filename.csv | more
However, it doesn't work because the first column cantains comma, thus 4th column is not really 4th. Below is an example of a row:
"sdfsdfsd, sfsdf", 454,fgdfg, I_want_this_column,sdfgdg,34546, 456465, etc
Unless you have specific reasons for using awk, I would recommend using a CSV parsing library. Many scripting languages have one built-in (or at least available) and they'll save you from these headaches.
if your first column has quotes always,
$ awk 'BEGIN{ FS="\042[ ]*," } { m=split($2,a,","); print a[3] } ' file
I_want_this_column
if the column you want is always the last 2nd,
$ awk -F"," '{print $(NF-1)}' file
I_want_this_column
You can try this demo script to break down the columns
awk 'BEGIN{ FS="," }
{
for(i=1;i<=NF;i++){
# save normal
if($i !~ /^[ ]*\042|[ ]*\042[ ]*$/){
a[++j]=$i
}
# if quotes at the end
if(f==1 && $i ~ /[ ]*\042[ ]*$/){
s=s","$i
a[++j]=s
#reset
s="";f=0
}
# if quotes in front
if($i ~ /^[ ]*\042/){
s=s $i
f=1
}
if(f==1 && ( $i !~/\042/ ) ){
s=s","$i
}
}
}
END{
# print columns
for(p=1;p<=j;p++){
print "Field "p,": "a[p]
}
} ' file
output
$ cat file
"sdfsdfsd, sfsdf", "454,fgdfg blah , words ", I_want_this_column,sdfgdg
$ ./shell.sh
Field 1 : "sdfsdfsd, sfsdf"
Field 2 : fgdfg blah
Field 3 : "454,fgdfg blah , words "
Field 4 : I_want_this_column
Field 5 : sdfgdg
You shouldn't use awk here. Use Python csv module or Perl Text::CSV or Text::CSV_XS modules or another real csv parser.
Related question -
parse csv file using gawk
If you can't avoid awk, this piece of code does the job you need:
BEGIN {FS=",";}
{
f=0;
j=0;
for (i = 1; i <=NF ; ++i) {
if (f) {
a[j] = a[j] "," $(i);
if ($(i) ~ "\"$") {
f = 0;
}
}
else {
++j;
a[j] = $(i);
if ((a[j] ~ "^\"[^\"]*$")) {
f = 1;
}
}
}
for (i = 1; i <= j; ++i) {
gsub("^\"","",a[i]);
gsub("\"$","",a[i]);
gsub("\"\"","\"",a[i]);
print "i = \"" a[i] "\"";
}
}
Working with CSV files that have quoted fields with commas inside can be difficult with the standard UNIX text tools.
I wrote a program called csvquote to make the data easy for them to handle. In your case, you could use it like this:
csvquote filename.csv | awk 'NR <2 {next}{FS =","}{print $4}' | csvquote -u | more
or you could use cut and tail like this:
csvquote filename.csv | tail -n +3 | cut -d, -f4 | csvquote -u | more
The code and docs are here: https://github.com/dbro/csvquote

Resources