Setup Factory 9 - Check File for String - scripting
Im am 100% new to Lua and need a way to check my etc/hosts file for a string. The other posts I found were dealing with searching in strings and and reading files line by line.
Here is some of my script which is a combination of some of the examples I found on here:
file = io.open("C:\Windows\System32\drivers\etc\hosts", "a")
function check(file)
if file.match(str, "nbs") then
file:close()
Screen.Next();
else
file:write("\n", %UserIP%, " nbs document")
file:close()
Screen.Next();
end
end;
As you can see Im searching the file hosts for the sting nbs. If it exists I want to move on. If it does not, I plan to append the file with a new line.
The above seems to do nothing when I enter it into my Lua Shell.
EDIT 1: adding full script; this is the full original script + my additions
-- These actions are performed when the Next button is clicked.
-- from _SUF70_Global_Functions.lua:
-- is the "Name:" field empty?
if(g_EditFieldIsEmpty(CTRL_EDIT_01)) then
-- the name field is empty...tell the user that it's a required field
-- and remain on this screen (don't advance to the next one)
-- "Invalid Entry"
local strTitle = SetupData.GetLocalizedString("MSG_INVALID_ENTRY");
-- get the label for the "Name:" edit field (since it may have been translated)
local strFieldName = DlgStaticText.GetProperties(CTRL_STATICTEXT_LABEL_01).Text;
-- strip off the trailing ":" (if present)
strFieldName = String.TrimRight(strFieldName, ":");
-- "The <fieldname> field cannot be empty."
local strPrompt = SetupData.GetLocalizedString("MSG_THE")
..strFieldName
..SetupData.GetLocalizedString("MSG_FIELD_CANNOT_BE_EMPTY");
Dialog.Message(strTitle, strPrompt, MB_OK, MB_ICONEXCLAMATION, MB_DEFBUTTON1);
else
--andrew you added the lines below
file = io.open("C:\Windows\System32\drivers\etc\hosts", "a")
function check(file)
if file.match(str, "test") then
file:close()
Screen.Next()
else
file:write("\n", "test")
file:close()
Screen.Next();
end
end;
-- the "Name:" field isn't empty...so
-- advance to the next screen
-- Screen.Next();
end;
This ended up being the solution I was looking for:
ip = SessionVar.Expand("%UserIP%")
result = TextFile.ReadToString(SessionVar.Expand("%SystemFolder%\\drivers\\etc\\hosts"));
if string.match(result, "nbs") then
Screen.Next()
else
file = io.open("C:\\Windows\\System32\\drivers\\etc\\hosts", "a")
file:write("\n", ip, " nbs document")
file:close()
Screen.Next()
end
In this case I was using the applications built in functions. These seem to make use of C as well so they would not work in a Lua shell.
Your code creates a file handle and defines a function check().
If it is supposed to do more you have to have to add more content. Like a function call to check.
Once you call check you'll most likely face a script error because you call a function file.match which does not exist in native Lua.
file = io.open("C:\Windows\System32\drivers\etc\hosts", "a")
-- this loop will give you each line of the file as a string and you can use string.match
for line in file:lines() do
if line:match("nbs") then
print("I found one!!")
end
end
I'm sure you can take it from here. Please refer to https://www.lua.org/manual/5.3/manual.html#6.8
Related
Rest of AppleScript is ignored when I use a variable in posix path
I'm using AppleScript in Automator to copy a page's source and save it to a file. For some reason when I use a variable (titleVal) in the posix path, the rest of my code in my loop is ignored, including the file that never gets written. I updated the code before with my full AppleScript in case it has to do with more than the few lines I had before. I'm using Automator with specified Finder items in this order: "urlList.txt" and fileList.txt". on run {input, parameters} set updateCount to 0 read (item 1 of input) set ps to paragraphs of the result set tot to count ps set TLFile to (("Users:Admin:Desktop:download captions:") as text) & "fileList.txt" set TLLines to paragraphs of (read file TLFile as «class utf8») tell application "Safari" reopen activate end tell repeat with i from 1 to tot set p to item i of ps if p is not "" then try tell application "Safari" tell front window set r to make new tab with properties {URL:"https://www.youtube.com/timedtext_editor?v=" & p & "&lang=en&name=&kind=&contributor_id=0&bl=vmp&action_view_track=1"} set current tab to r set titleVal to item i of TLLines set updateCount to updateCount + 1 do shell script "echo The value: " & updateCount delay 2 do JavaScript "document.getElementById('movie_player').outerHTML = ''" in current tab do JavaScript "document.getElementById('creator-page-sidebar').outerHTML = ''" in current tab do JavaScript "document.getElementById('footer').outerHTML = ''" in current tab delay 3 do JavaScript "document.getElementsByClassName('yt-uix-button yt-uix-button-size-default yt-uix-button-default action-track-button flip yt-uix-menu-trigger')[0].click()" in current tab delay 1 do JavaScript "document.getElementById('aria-menu-id-2').getElementsByTagName('ul')[0].getElementsByTagName('li')[5].getElementsByTagName('a')[0].click()" in current tab delay 4 -- using a variable in path1 is where it screws up. try changing it to another variable value and it will have the same effect. set myString to source of current tab set path1 to "/Users/Admin/Desktop/download captions/downloadedCaptions/" & titleVal & ".srt" say path1 set newFile to POSIX file path1 --set newFile to POSIX file "/Users/Admin/Desktop/download captions/downloadedCaptions/test.xml.srt" open for access newFile with write permission write myString to newFile close access newFile -- i have exit repeat here to only test the first loop exit repeat end tell end tell end try end if end repeat end run Without a variable works fine, but I need the variable to make the script work properly in a loop. I've checked the value of the var. I also tried "& quoted form of titleVal &". Update: When I remove the try/end try as suggested to get the error, the error is: The action “Run AppleScript” encountered an error: “Safari got an error: Can’t get POSIX file "/Users/Admin/Desktop/download captions/downloadedCaptions/test.srt" of window 1.”
The error occurs because you are going to write the file in the tell window block of Safari which cannot work. I recommend to use a separate handler. Put the on writeFile handler outside of the on run handler. I added reliable error handling and the data are saved UTF-8 encoded. on writeFile(theData, fileName) set newFile to "/Users/Admin/Desktop/download captions/downloadedCaptions/" & fileName & ".srt" try set fileDescriptor to open for access newFile with write permission write theData to fileDescriptor as «class utf8» close access fileDescriptor on error try close access newFile end try end try end writeFile and call it (replace the part of your code from delay 4 to the end) delay 4 -- using a variable in path1 is where it screws up. try changing it to another variable value and it will have the same effect. set myString to source of current tab my writeFile(myString, titleVal) exit repeat end tell end tell end try end if end repeat end run
This was fixed very easily by changing one line: set newFile to POSIX file path1 to: set newFile to (path1 as POSIX file) But I don't know why. Seems like a bug since it worked without the variable. Please provide any details in the comments why this works over the original set newFile line.
How to skip to next in a list if vba can't find a file
I have a code that uses a list of company names, a code then converts these to file destinations and then another code goes through each and opens them and takes values off of each. e.g. Admiral_Group-2015-AR converts to C:\Users\Jon\Desktop\CodeBackups\Companies\Admiral_Group-2015-AR.xlsx (FSOURCE) The issue I have is that I do not have all the files for the ones in the list yet and so the code errors when it cannot find a file. How can I make it skip to the next file in the loop instead? This is the part of code that I have: For startno = 1 To endno If IsEmpty(WS_Companies.Range("A:A").Find(what:="File Name").Offset(startno, 0).Value) = False Then FSource = WS_Companies.Range("A:A").Find(what:="File Name").Offset(startno, 1).Value Set WB_Report = Workbooks.Open(FSource) Thanks
Check for its existence with Dir$() before attempting to open it: If Len(Dir$(FSource)) then '// file exists on disk Set WB_Report = Workbooks.Open(FSource) ... End if
VBA.FileSystem Dir
In VB6 code i m using VBA.FileSystem.Dir to get file name from a directory path. But it is returning empty string. Please find the below code Call getFile.ShowOpen //getFile is CommonDialog Control of VB6 txtFile.Text = getFile.FileTitle //Correct file name is returned If Dir(getFile.filename) == "" Then // Conditions come true..But ideally it should not!!! But the file resides in some network location. Can there be any permission issue? If yes, How do i see that file in getFile.ShowOpen dialog and Dir() returns empty string? Any help on what is wrong in the above code
Consider these points: afaik, the double equal ( == ) is not supported in vb6 Dir = (whatever) can return "" if whatever is a directory or hidden file You could trap just the name by using If Dir(whatever, vbDirectory Or vbHidden Or vbArchive Or vbNormal) But you would still have to test each to see what it was. btw, it's better to have a variable to receive Dir and inspect that, rather than inspecting Dir itself. dim sTgt$ sTgt = Dir(whatever) Also, btw, an alternative to chking each type is to to inspect FileLen. Curiously, FileLen was not affected by the Hidden/Sys attribs, although it will err out if the file does not exist. So, (and this is really old hacking stuff but handy code). If you declare a variable for FileLen Dim lfLen& 'and have some error coding On Error resume next 'and then just inspect the target lfLen = FileLen(stgt) if lflen > 0 then ... do things (or if hacking) ... binary open Because, If the file no exist, a directory will return 0, but if file = archive, hidden, sys it will return bytes. hth Gary
VBS Read Variable NAME and Data from file
I am creating a script that will contain variables that need to be set by the user. I created an ini file where those variables can be defined by the user without having to mess with the script itself. I need the VBS script to be able to read the file and create a variable based on the first part of the line and then set the value of that variable based on the second part of that line. The ini file looks something like this path=C:\users\whatever filename=whatever.txt FileTypes=txt,doc,mp3,etc In a batch file, this is easy, you can simply do: for /f "delims=" %%x in (config.ini) do (set "") I would love if there is an equally simple answer in VBS, but here is what I have (working) filename = "config.ini" Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.OpenTextFile(filename) Do Until f.AtEndOfStream LineArray = Split(f.ReadLine , "=") Select Case LineArray(0) Case "path" path = LineArray(1) Case "filename" fname = LineArray(1) Case "FileTypes" FileTypes = LineArray(1) End Select Loop f.Close This works, but I essentially had to rename my variables myself, and the script is more difficult to maintain and not as efficient. It would be nice if I could replace the case statement with something more like DIM "LineArray(0)"=LineArray(1) and have VBS recognize that LineArray(0) should be defined as a new variable using the value of LineArray(0) as the name of the variable. Is there a way to do this in VBS?
Execute (or ExecuteGlobal) will do what you want with the input you described. I would advise caution, though, because these statements will not only define variables, but execute any code passed into them. Using a dictionary is a safer approach: Set ini = CreateObject("Scripting.Dictionary") Do Until f.AtEndOfStream line = f.ReadLine If InStr(line, "=") > 0 Then arr = Split(line, "=", 2) ini(Trim(arr(0))) = arr(1) End If Loop WScript.Echo ini("path") Particularly if you want to handle actual INI files, which may consist of several sections (and also contain comments): [section1] foo = "something" bar = 42 [section2] ;this is a comment foo = "something" baz = 23 I wrote such an INI parser myself a couple years ago. You can find it on my blog.
I figured it out. The answer is Execute. The simple line I needed was: Execute(LineArray(0) + " = " + "LineArray(1)")
Validate a csv file
This is my sample file #%cty_id1,#%ccy_id2,#%cty_src,#%cty_cd3,#%cty_nm4,#%cty_reg5,#%cty_natnl6,#%cty_bus7,#%cty_data8 690,ALL2,,AL,ALBALODMNIA,,,, 90,ALL2,,,AQ,AKNTARLDKCTICA,,, 161,IDR2,,AZ,AZLKFMERBALFKIJAN,,,, 252,LTL2,,BJ,BENLFMIN,,,, 206,CVE2,,BL,SAILFKNT BAFSDRTHLEMY,,,, 360,,,BW2,BOPSLFTSWLSOANA,,,, The problem is for #%cty_cd3 is a standard column(NOT NULL) with length 2 letters only, but in sql server the record shifts to the other column,(due to a extra comma in btw)how do i validate a csv file,to make sure that when there's a 2 character word need to be only in 4 column? there are around 10000 records ? Set of rules Defined ! Should have a standard set of delimiters for eachrow if not Check for NOT NULL values having Null values If found Null remove delimiter at the pointer The 3 ,,, are not replaced with 2 ,, #UPDATED : Can i know if this can be done using a script ? Updated i need only a function That operates on records like 90,ALL2,,,AQ,AKNTARLDKCTICA,,, correct them using a Regex or any other method and put back into the source file !
Your best bet here may be to use the tSchemaComplianceCheck component in Talend. If you read the file in with a tFileInputDelimited component and then check it with the tSchemaComplianceCheck where you set cty_cd to not nullable then it will reject your Antarctica row simply for the null where you expect no nulls. From here you can use a tMap and simply map the fields to the one above. You should be able to easily tweak this as necessary, potentially with further tSchemaComplianceChecks down the reject lines and mapping to suit. This method is a lot more self explanatory and you don't have to deal with complicated regex's that need complicated management when you want to accommodate different variations of your file structure with the benefit that you will always capture all of the well formatted rows.
You could try to delete the empty field in column 4, if column no. 4 is not a two-character field, as follows: awk 'BEGIN {FS=OFS=","} { for (i=1; i<=NF; i++) { if (!(i==4 && length($4)!=4)) printf "%s%s",$i,(i<NF)?OFS:ORS } }' file.csv Output: "id","cty_ccy_id","cty_src","cty_nm","cty_region","cty_natnl","cty_bus_load","cty_data_load" 6,"ALL",,"AL","ALBANIA",,,, 9,"ALL",,"AQ","ANTARCTICA",,, 16,"IDR",,"AZ","AZERBAIJAN",,,, 25,"LTL",,"BJ","BENIN",,,, 26,"CVE",,"BL","SAINT BARTH�LEMY",,,, 36,,,"BW","BOTSWANA",,,, 41,"BNS",,"CF","CENTRAL AFRICAN REPUBLIC",,,, 47,"CVE",,"CL","CHILE",,,, 50,"IDR",,"CO","COLOMBIA",,,, 61,"BNS",,"DK","DENMARK",,,, Note: We use length($4)!=4 since we assume two characters in column 4, but we also have to add two extra characters for the double quotes..
The solution is to use a look-ahead regex, as suggested before. To reproduce your issue I used this: "\\,\\,\\,(?=\\\"[A-Z]{2}\\\")" which matches three commas followed by two quoted uppercase letters, but not including these in the match. Ofc you could need to adjust it a bit for your needs (ie. an arbitrary numbers of commas rather than exactly three). But you cannot use it in Talend directly without tons of errors. Here's how to design your job: In other words, you need to read the file line by line, no fields yet. Then, inside the tMap, do the match&replace, like: row1.line.replaceAll("\\,\\,\\,(?=\\\"[A-Z]{2}\\\")", ",,") and finally tokenize the line using "," as separator to get your final schema. You probably need to manually trim out the quotes here and there, since tExtractDelimitedFields won't. Here's an output example (needs some cleaning, ofc): You don't need to entry the schema for tExtractDelimitedFields by hand. Use the wizard to record a DelimitedFile Schema into the metadata repository, as you probably already did. You can use this schema as a Generic Schema, too, fitting it to the outgoing connection of tExtractDelimitedField. Not something the purists hang around, but it works and saves time. About your UI problems, they are often related to file encodings and locale settings. Don't worry too much, they (usually) won't affect the job execution. EDIT: here's a sample TOS job which shows the solution, just import in your project: TOS job archive EDIT2: added some screenshots
Coming to the party late with a VBA based approach. An alternative way to regex is to to parse the file and remove a comma when the 4th field is empty. Using microsoft scripting runtime this can be acheived the code opens a the file then reads each line, copying it to a new temporary file. If the 4 element is empty, if it is it writes a line with the extra comma removed. The cleaned data is then copied to the origonal file and the temporary file is deleted. It seems a bit of a long way round, but it when I tested it on a file of 14000 rows based on your sample it took under 2 seconds to complete. Sub Remove4thFieldIfEmpty() Const iNUMBER_OF_FIELDS As Integer = 9 Dim str As String Dim fileHandleInput As Scripting.TextStream Dim fileHandleCleaned As Scripting.TextStream Dim fsoObject As Scripting.FileSystemObject Dim sPath As String Dim sFilenameCleaned As String Dim sFilenameInput As String Dim vFields As Variant Dim iCounter As Integer Dim sNewString As String sFilenameInput = "Regex.CSV" sFilenameCleaned = "Cleaned.CSV" Set fsoObject = New FileSystemObject sPath = ThisWorkbook.Path & "\" Set fileHandleInput = fsoObject.OpenTextFile(sPath & sFilenameInput) If fsoObject.FileExists(sPath & sFilenameCleaned) Then Set fileHandleCleaned = fsoObject.OpenTextFile(sPath & sFilenameCleaned, ForWriting) Else Set fileHandleCleaned = fsoObject.CreateTextFile((sPath & sFilenameCleaned), True) End If Do While Not fileHandleInput.AtEndOfStream str = fileHandleInput.ReadLine vFields = Split(str, ",") If vFields(3) = "" Then sNewString = vFields(0) For iCounter = 1 To UBound(vFields) If iCounter <> 3 Then sNewString = sNewString & "," & vFields(iCounter) Next iCounter str = sNewString End If fileHandleCleaned.WriteLine (str) Loop fileHandleInput.Close fileHandleCleaned.Close Set fileHandleInput = fsoObject.OpenTextFile(sPath & sFilenameInput, ForWriting) Set fileHandleCleaned = fsoObject.OpenTextFile(sPath & sFilenameCleaned) Do While Not fileHandleCleaned.AtEndOfStream fileHandleInput.WriteLine (fileHandleCleaned.ReadLine) Loop fileHandleInput.Close fileHandleCleaned.Close Set fileHandleCleaned = Nothing Set fileHandleInput = Nothing KillFile (sPath & sFilenameCleaned) Set fsoObject = Nothing End Sub
If that's the only problem (and if you never have a comma in the field bt_cty_ccy_id), then you could remove such an extra comma by loading your file into an editor that supports regexes and have it replace ^([^,]*,[^,]*,[^,]*,),(?="[A-Z]{2}") with \1.
i would question the source system which is sending you this file as to why this extra comma in between for some rows? I guess you would be using comma as a delimeter for importing this .csv file into talend. (or another suggestion would be to ask for semi colon as column separator in the input file) 9,"ALL",,,"AQ","ANTARCTICA",,,, will be 9;"ALL";,;"AQ";"ANTARCTICA";;;;