How to have Autohotkey 'listen' for a change to a file? - autohotkey

I have a text file, lets call it C:\to_run.txt. I'd like my Autohotkey script to 'listen' to this file in such a way that when it detects a change, it performs an action immediately based on the contents of the file, and then make the file blank again.
I can handle the last parts, so really I'm asking for an efficient way to detect file changes? I say efficient because my Autohotkey script is getting rather long and I don't want this listening function to hang up the rest of the script in any way.

Assuming we are really talking of only one file to check on:
Surely not as beautiful as Sidola's answer, but without the need for external libraries:
#persistent
lastFileContent := ""
setTimer, checkFile, 20
return
checkFile:
fileread newFileContent, changingDocument.txt
if(newFileContent != lastFileContent) {
lastFileContent := newFileContent
msgbox, content changed to: %newFileContent%
}
return
In this case, for checking on larger files, it might be better to compare MD5-checksums instead of the whole file content.
Note: I have not tested the performance implications on this. This script opens up the file 50 times per second, could be pretty hard drive consuming.

Check out WatchDirectory()
Just make sure you're running the latest version of AHK.
To get it up and running, first download these three scripts and save them to your /lib folder.
WatchDirectory.ahk
_Struct.ahk
sizeof.ahk
After that, simply point to to wherever you want to look, provide a callback function and if you want, a third param to watch for specific changes. Refer to this forum post for full documentation.
If you drop this script in its own folder, save it and run it, then save it again, it should detect changes to that script file.
#Persistent
WatchDirectory(A_ScriptDir "\|.ahk\", "Callback", 0x10)
return
Callback(param1, param2) {
msgBox % param1 "`n" param2
}
Note however, it will fire twice whenever the file is changed. This seems to be a Windows behaviour from what I can gather.

Related

How to replace value in txt file with powershell from GitHub

I want to build a simple script that may be useful for others as well, but I have only very basic programming knowledge and can't do it myself without learning how to write powershell scripts from scratch.
What this script is supposed to do is, open an INI file (really just a txt), look for a variable with an assigned value and replace that value from a txt hosted on GitHub, save and then run a program.
This is for the tracker list of qBittorrent, since that feature still hasn't been implemented and the only other script that I could find that does this is for linux and mac, there seem to be none for windows.
The basic idea is this:
get-content "c:\users\[user]\appdata\roaming\qbittorrent\qbittorrent.ini"
# This is where pseudo code starts
get file from "[github-link.txt]"
save file to cache # keeping it is useless as it gets updated daily
find variable "Session\AdditionalTrackers=" in qbittorrent.ini
replace value of variable with content of cached file # this is what I struggle with most when looking for example code. Everything I could find specified the exact string that needed replacing, which in this case is quite long and may change with every update of the file.
overwrite original file
launch program qbittorrent.exe
end script
Conveniently or most likely deliberately all (most) of the tracker lists on GitHub are already formatted in a way that they can be directly pasted into the file without having to worry about formatting. Example.
I can totally understand if nobody wants to do the work, but I would greatly appreciate it and possibly others that are looking for a stopgap for the lacking feature.
If this already exists, go ahead and call me an idiot and while you're at it drop a link ;)
I just found a little tool called Power Automate and it pretty much does what I was looking for. It's not quite as elegant as a single click script but it does the job. Sadly I can't share the "flow" I built because, well, there is no option for it - thanks Microsoft. So, I'll try my best to write it out.
Not quite a "solution" but pretty to close to it.
Here is the "flow":
get file from web // from github for example
read text from file // read downloaded .txt file
read text from file // read qBittorrent.ini
crop text // crop between flags in qBittorrent.ini use "Session\AdditionalTrackers=" as start and "Session\GlobalMaxRatio=" as end and save to cropVar2
crop text // crop before flag use "Session\AdditionalTrackers=" as flag and save to cropVar1
crop text // crop after flag use cropVar2 as flag and save to cropVar3
replace text // replace cropVar2 with content of downloaded file and save to cropVar2
write text to file // write cropVar1,cropVar2,cropVar3
end flow
Keep in mind that any changes to the qBittorrent.ini may change the order of the entries. Which means you have to check if it's still correct after every update and after every change you make in the options. This is a massive cludge after all...
You can input fail saves so that you won't break anything if the order changed.

MATLAB doesn't find files I downloaded while the script is running

My problem is as described. My script downloads files through an external call to cmd (using the system function and then .NET to make keypresses). The issue is that when it tries to fopen these files I downloaded (filenames from a text file I write as I download), it doesn't find them, causing an error. When I run the script again after seeing it fail, it works but only up to the point where it's trying to download/call new files again, where it runs into the same problem.
Are new files downloaded during when a script is running somehow not visible to the search path? Because the folder is most definitely in my search path (seeing as it works outside of during-script downloads). It's not that it isn't getting the files fast enough either, cause they appear in my folder almost instantly, and I've tried a delay to allow for it to recognize it, but that didn't work either.
I'm not sure if it's important to note that the script calls an external function which tries to read the files from the .txt list I create in the main script.
Any ideas?
The script to download the files looks like so:
NET.addAssembly('System.Windows.Forms');
sendkey = #(strkey) System.Windows.Forms.SendKeys.SendWait(strkey);
system('start cygwinbatch.bat')
pause(.1)
sendkey(callStr1)
sendkey('{ENTER}')
pause(.1)
sendkey(callStr2)
sendkey('{ENTER}')
pause(.1)
sendkey('exit')
pause(2)
sendkey('{ENTER}')
But that is not the main reason I am asking: I am confident that the downloads are occurring when the script calls them, because I see them appearing in my folder as it called. I am more confused as to why MATLAB doesn't seem to know they are there while the script is running, and I have to stop it and run it again for it to recognize the ones I've downloaded already.
Thank you,
Aaron
The answer here is probably to run the 'rehash' function. Matlab does not look for new files while executing an operation, and in some environments misses new files even during interactive activity.
Running the rehash function forces Matlab to search through its full path and determine if there are any new files.
I've never tried to run rehash in the middle of an operation though. ...
My guess is that the MATLAB interpreter is trying to look ahead and is throwing errors based on a snapshot of what the filesystem looked like before the files were downloaded. Do you get different behavior if you run it one line at a time using F9? If that's the case then you may be able to prevent the interpreter from looking ahead by using eval().

AHK - Read .txt from website?

So, I can make my AHK script read from an local file, but I'd like to make it read from an remote file. (on an website)
I could download the file locally and then read it but that's not what I want as I want to update the .txt from time to time without having to making the script re-download each time on start up.
So I've tried to do something like this:
FileRead, output, woop.txt
MsgBox, %output%
And boy, it worked fine! But like I said, that's for the local file. Now I tried to do the exact same with but with an link instead:
FileRead, output, http://mywebsite.net/woop.txt
MsgBox, %output%
(and yes, the file is on my site, just another domain)
However, it just returns null/nothing, so I'm curious how I'd go about doing this? I've tried to use Google etc, but haven't found an answer. Thanks in advance.
In the Autohotkey documentation, there is this:
UrlDownloadToFile, URL, Filename
It is supposed to download the file. If it were a text file, you could download it and then read it.
If you want to see if you have an internet connection first, you could do this:
;example
If ConnectedToInternet()
Msgbox, 64, WinInet.dll, ONLINE!
else
Msgbox, 48, WinInet.dll, OFFLINE!
Return
ConnectedToInternet(flag=0x40) {
Return DllCall("Wininet.dll\InternetGetConnectedState", "Str", flag,"Int",0)
}
And I don't see any reason why the text file has to be in your domain. In fact, you could download and read any file you wanted, so long as you could call it up in a browser.

Automatically running a script to read particular information from a .txt file ? (Perl Script, or suggest)

My scenario: A text file(s) will keep coming into say a folder, I need to detect the new text file, and read particular information from it, say format being (word : info, OR word and under it a column of info, etc.). And, this process needs to keep going on always.
Problem: How should I go about doing this, I guess use perl scipt, but where to go from there ?, I am getting ideas, and also help on the internet, but I thought asking it here might make my thoughts clearer.
Kindly help, please suggest a path to do this.
Regards,
Chirayu
First thing: you want a daemon process, so you may want to have a look at Proc::Daemon.
Second thing, you need to read & parse your file. Parsing it, depends on its format, and your question is not really clear about it.
Finally, you may want to consider moving a newly detected file (or renaming it) while processing it, end then (possibly) deleting it after having processed. This depends on the requirements that you have. Alternatively, you may want to move the newly detected file into an archive directory after having processed them.
One approach might be to have a perl process that regularly (say every 5 seconds, every 5 minutes or every 5 hours, your call really) scans said directory and as soon as any new text file appears, spawn a child process that process it.
The child process might be another perl script which gets the name of the text file as it's argument and which reads the file, detects the word you mention and then extracts the information you are interested in (and then does whatever you consider necessary with that information).
Things to look out for is what to do with the text files once they are processed. Are they supposed to stay around? Then you need to keep track of which of them you have processed, so they do not get processed again in the case your master process (the one that scans the directory and spawn perl children) has to be restarted (due to either a crash or a deliberate restart).
If the text files are supposed to disappear once they are processed, then I assume it could be a good idea to either let the children remove them after completion or to let the master process remove them provided the master process always waits for the children to complete before it continues running. The drawback with a master process waiting for children to complete is that children then cannot be run in parallell but has to be run in strict sequence (not necessary a drawback depending on your situation).
(If you have a master process always waiting for the child process to run, you can actually skip having child processes altogether and create a subroutine in the master program which reads and processes the text file).
High level description but hope it helps.
What is the operating system you are using?
On Windows, you can use Win32::ChangeNotify and on Linux, you can use Linux::Inotify2 to be notified of changes to the contents of a directory.
Your script can simply wait to be notified and take action when notified instead of polling the contents of the directory which will either waste resources or potentially miss some changes.

Monitoring File Changes

Call CreateObject("WScript.Shell").Run(some.exe,0,False)
I'm using that line to call a .exe that returns some text, but can also write it to a file.
I would use .Exec instead of .Run to get the results directly but then the script hangs.
I really don't want a timer checking if the output file is created or modified.
What I need is a way to catch an event somehow. Any Ideas?
Since you mention that it might either return it or write it to a file, does that mean that after the process has written to the file it'll exit?
If so, you could just call the Shell.Run method with the bWaitOnReturn parameter set to True and your script would wait for the process to finish before it continued.
Otherwise, if the process might write a file and then still continue to run, then I think you will have to poll to check if it exists, or possibly you could create a C# or VB.Net exe that uses FileSystemWatcher (or a normal Win32 exe that uses the API FindFirstChangeNotification) to look for the creation of the file and when it finds one it immediately exists and then you could run that process with bWaitOnReturn set to True, but that's probably just overcomplicating things.