 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
xx3nvyxx
Joined: 05 Sep 2005 Posts: 86 Location: Down the hall, on your left.
|
Posted: Thu Mar 06, 2008 3:41 am Post subject: Wildcard Folders |
|
|
I would like to be able to do this:
| Code: | loop, %A_AppData%\.purple\logs\aim\*\randomsn\*.html
{
Filelist := FileList "," A_loopFileName
} |
The function would be to allow one folder (or multiple folders, but only if seperated by a \) to be variable and still be able to build a file list.
If you want a can build a "proof of concept" function, but I really would like to see it added to ahk itself.
Edit: Built the "proof of concept" function. I will keep this post up to date with the newest version, just in case it breaks or I add new features.
Version 1.1
| Code: | ;
; AutoHotkey Version: 1.0.47.5
; Language: English
; Platform: WinXP Pro
; Author: William Washco <xx3nvyxx@gmail.com>
;
; Script Function:
; Convert paths with wildcards to a file list.
;
/*
#singleinstance, force
WildcardFolder = C:\Program Files\*\*\
File = *.exe
List := WildcardFolderList(WildcardFolder,File)
msgbox, %List%
Return
*/
WildcardFolderList(Path,FilePattern)
{
StringReplace, Newpath, Path, *\, ¤,A
StringSplit, Folders, Newpath, ¤
Loops := Folders0 - 1
Folders1 := Folders1 . "*"
Loop, %Loops%
{
Nextlevel := ""
TempList := ""
Wildcard := ""
loop, parse, Folders%A_Index%, `,
{
loop, %A_LoopField%, 2
{
If (NextLevel != "")
NextLevel := NextLevel . "," . A_LoopFileLongPath
Else
NextLevel := A_LoopFileLongPath
}
}
Next := A_Index + 1
If (A_Index != Loops)
Wildcard := "*"
Loop, parse, NextLevel, `,
{
If (A_Index != 1)
TempList := TempList . "," A_LoopField . "\" . Folders%Next% . Wildcard
Else
TempList := A_LoopField . "\" . Folders%Next% . Wildcard
}
Folders%Next% := TempList
}
FoundFolders := 0
loop, parse, TempList, `,
{
Ifexist, %A_LoopField%
{
If (FolderListing != "")
FolderListing := FolderListing . "," . A_LoopField
Else
FolderListing := A_LoopField
}
}
Loop, parse, FolderListing, `,
{
WildFile := A_LoopField . "\" . FilePattern
TempFileList := ""
Loop, %WildFile%
{
If (TempFileList != "")
TempFileList := TempFileList . "," . A_LoopFileLongPath
Else
TempFileList := A_LoopFileLongPath
}
If (TempFileList = "")
continue
If (A_Index != 1)
FileList := FileList . "," . TempFileList
Else
FileList := TempFileList
}
Return, FileList
} |
*NOTE* My code posted here has been pointed out to NOT be the best solution. Please read further for code as short as 9 lines long. Including the function header and curly braces. _________________ Now the world has gone to bed,
Darkness won't engulf my head,
I can see by infra-red,
How I hate the night.
Now I lay me down to sleep,
Try to count electric sheep,
Sweet dream wishes you can keep,
How I hate the night.
Last edited by xx3nvyxx on Sat Mar 08, 2008 5:44 pm; edited 3 times in total |
|
| Back to top |
|
 |
LBJ
Joined: 03 May 2007 Posts: 16
|
Posted: Thu Mar 06, 2008 6:43 am Post subject: |
|
|
I absolutely agree that the *nix style of wildcard globbing is a truly elegant tool when used with certain file structures.
Web servers and mail servers in particular are very easily controlled with a simple glob like...
/home/*/public_html/*/config.php
...to pick up...
/home/fred/public_html/mail-app/config.php
/home/mary/public_html/mail-app/config.php
/home/mary/public_html/another-app/config.php
It would definitely be nice if the standard loop function provided extended *nix globbing rather than have to code a function wrapper to emulate it. |
|
| Back to top |
|
 |
xx3nvyxx
Joined: 05 Sep 2005 Posts: 86 Location: Down the hall, on your left.
|
Posted: Thu Mar 06, 2008 7:03 am Post subject: |
|
|
Speaking of a wrapper, I am nearing the completion of my (very messy) function to do just that. I hope that, should it not be implemented into the next version of AHK, it is at least cleaned up by someone more talented than myself.
More news when I'm done.
Don't bother me, I'm coding. _________________ Now the world has gone to bed,
Darkness won't engulf my head,
I can see by infra-red,
How I hate the night.
Now I lay me down to sleep,
Try to count electric sheep,
Sweet dream wishes you can keep,
How I hate the night. |
|
| Back to top |
|
 |
xx3nvyxx
Joined: 05 Sep 2005 Posts: 86 Location: Down the hall, on your left.
|
Posted: Thu Mar 06, 2008 8:32 am Post subject: |
|
|
| Code: | #singleinstance, force
WildcardFolder = %A_AppData%\.purple\logs\*\*\randomsn\
File = *.html
List := WildcardFolderList(WildcardFolder,File)
msgbox, %List%
Return
WildcardFolderList(Path,FilePattern)
{
StringReplace, Newpath, Path, *\, ¤,A
StringSplit, Folders, Newpath, ¤
Loops := Folders0 - 1
Folders1 := Folders1 . "*"
Loop, %Loops%
{
Nextlevel := ""
TempList := ""
Wildcard := ""
loop, parse, Folders%A_Index%, `,
{
loop, %A_LoopField%, 2
{
If (NextLevel != "")
NextLevel := NextLevel . "," . A_LoopFileLongPath
Else
NextLevel := A_LoopFileLongPath
}
}
Next := A_Index + 1
If (A_Index != Loops)
Wildcard := "*"
Loop, parse, NextLevel, `,
{
If (A_Index != 1)
TempList := TempList . "," A_LoopField . "\" . Folders%Next% . Wildcard
Else
TempList := A_LoopField . "\" . Folders%Next% . Wildcard
}
Folders%Next% := TempList
}
FoundFolders := 0
loop, parse, TempList, `,
{
Ifexist, %A_LoopField%
{
FoundFolders += 1
If (FoundFolders != 1)
FolderListing := FolderListing . "," . A_LoopField
Else
FolderListing := A_LoopField
}
}
Loop, parse, FolderListing, `,
{
WildFile := A_LoopField . "\" . FilePattern
Loop, %WildFile%
{
If (A_Index != 1)
TempFileList := TempFileList . "," . A_LoopFileLongPath
Else
TempFileList := A_LoopFileLongPath
}
If (A_Index != 1)
FileList := FileList . "," . TempFileList
Else
FileList := TempFileList
}
Return, FileList
} |
Here it is: V1.0
Note the path and file name are seprate. Also note the (not required) trailing backslash on the path. If you make a habit of including it it will be easier to remember the (required) trailing backslash if the path ends in a wildcard. _________________ Now the world has gone to bed,
Darkness won't engulf my head,
I can see by infra-red,
How I hate the night.
Now I lay me down to sleep,
Try to count electric sheep,
Sweet dream wishes you can keep,
How I hate the night. |
|
| Back to top |
|
 |
xx3nvyxx
Joined: 05 Sep 2005 Posts: 86 Location: Down the hall, on your left.
|
Posted: Thu Mar 06, 2008 6:40 pm Post subject: |
|
|
| Code: | ;
; AutoHotkey Version: 1.0.47.5
; Language: English
; Platform: WinXP Pro
; Author: William Washco <xx3nvyxx@gmail.com>
;
; Script Function:
; Convert paths with wildcards to a file list.
;
/*
#singleinstance, force
WildcardFolder = C:\Program Files\*\*\
File = *.exe
List := WildcardFolderList(WildcardFolder,File)
msgbox, %List%
Return
*/
WildcardFolderList(Path,FilePattern)
{
StringReplace, Newpath, Path, *\, ¤,A
StringSplit, Folders, Newpath, ¤
Loops := Folders0 - 1
Folders1 := Folders1 . "*"
Loop, %Loops%
{
Nextlevel := ""
TempList := ""
Wildcard := ""
loop, parse, Folders%A_Index%, `,
{
loop, %A_LoopField%, 2
{
If (NextLevel != "")
NextLevel := NextLevel . "," . A_LoopFileLongPath
Else
NextLevel := A_LoopFileLongPath
}
}
Next := A_Index + 1
If (A_Index != Loops)
Wildcard := "*"
Loop, parse, NextLevel, `,
{
If (A_Index != 1)
TempList := TempList . "," A_LoopField . "\" . Folders%Next% . Wildcard
Else
TempList := A_LoopField . "\" . Folders%Next% . Wildcard
}
Folders%Next% := TempList
}
FoundFolders := 0
loop, parse, TempList, `,
{
Ifexist, %A_LoopField%
{
If (FolderListing != "")
FolderListing := FolderListing . "," . A_LoopField
Else
FolderListing := A_LoopField
}
}
Loop, parse, FolderListing, `,
{
WildFile := A_LoopField . "\" . FilePattern
TempFileList := ""
Loop, %WildFile%
{
If (TempFileList != "")
TempFileList := TempFileList . "," . A_LoopFileLongPath
Else
TempFileList := A_LoopFileLongPath
}
If (TempFileList = "")
continue
If (A_Index != 1)
FileList := FileList . "," . TempFileList
Else
FileList := TempFileList
}
Return, FileList
} |
V1.1
-Fixed a bug which caused the function to return the same file "a number" of times if it could not find FilePattern in "a number" of folders.
-Changed the default path to something most people will get results on.
-The test case is commented out to make including this function easier. _________________ Now the world has gone to bed,
Darkness won't engulf my head,
I can see by infra-red,
How I hate the night.
Now I lay me down to sleep,
Try to count electric sheep,
Sweet dream wishes you can keep,
How I hate the night. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2472 Location: Australia, Qld
|
Posted: Fri Mar 07, 2008 2:02 am Post subject: |
|
|
Why not simply...
| Code: | Loop, %A_AppData%\.purple\logs\aim\*, 2
{
Loop, %A_LoopFileLongPath%\randommsn\*.html
{
;...
}
} |  |
|
| Back to top |
|
 |
xx3nvyxx
Joined: 05 Sep 2005 Posts: 86 Location: Down the hall, on your left.
|
Posted: Fri Mar 07, 2008 2:15 am Post subject: |
|
|
That can't exactly be used for multiple applications. My function allows for any number of wildcard folders. _________________ Now the world has gone to bed,
Darkness won't engulf my head,
I can see by infra-red,
How I hate the night.
Now I lay me down to sleep,
Try to count electric sheep,
Sweet dream wishes you can keep,
How I hate the night. |
|
| Back to top |
|
 |
LBJ
Joined: 03 May 2007 Posts: 16
|
Posted: Sat Mar 08, 2008 7:27 am Post subject: |
|
|
| lexiKos wrote: | Why not simply...
| Code: | Loop, %A_AppData%\.purple\logs\aim\*, 2
{
Loop, %A_LoopFileLongPath%\randommsn\*.html
{
;...
}
} |  |
Until you've used unix style globbing, it's hard to appreciate the benefit of it, or even to immediately see the difference.
However, once you've used it, it's horrible to work without it.
The code stub you've provided above relies on the coder or application providing the full path to the ultimate folder where the *.html files are to be found. That's fairly trivial compared to what unix globbing provides.
Imagine a web server with the following structure...
/home (or c:\home for Window/Dos syntax)
Under the /home folder are all private folders for all users. Let's work with tom, mary, sue, sally and bob, so...
/home/tom
/home/mary
/home/sue
/home/sally
/home/bob
Under each of those private folders is their root web folder, usually called public_html, so...
/home/tom/public_html
/home/mary/public_html
/home/sue/public_html
/home/sally/public_html
/home/bob/public_html
We could carry that on to a great depth, but let's now assume we want to delete all *.html files in each of those public_html folders, and *ONLY* in those public_html folders, so...
rm (or del for Windows) /home/*/public_html/*.html
That's totally different to standard Windows globbing as provided via the Loop, FilePattern routine of AHK.
As one more example, imagine we only wanted to delete the .pl files owned by sue and sally and only if they're in a folder under the public_html folder and only for folders with a g in the second position like cgi-bin, so...
rm /home/s*/public_html/?g*/*.pl
We run mostly *nix servers, but we also manage a lot of windows boxes, so one of the first things we code for any language we're using away from *nix is a globbing extension.
Our globbing for AHK is part of a larger routine we use for the admin of our email servers, but I've massaged out the basic routines and created a standalone function. It handles all standard globs using * and ? and accepts an optional secondary parameter to specify how to handle folders found at the final level similar to AHK's Loop, Filepattern, IncludeFolders syntax.
Relative and absolute path referencing are supported.
Typical calls could be of the form...
List := UnixGlob("C:\Program Files\*\o??ic*\*.exe")
...or to include/require folders at the final level...
List := UnixGlob("C:\Program Files\*\o??ic*\*.exe", [1/2])
Edit: For a truly elegant coding solution, see the post from lexiKos below...
Last edited by LBJ on Sun Mar 09, 2008 12:33 am; edited 2 times in total |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2472 Location: Australia, Qld
|
Posted: Sat Mar 08, 2008 1:01 pm Post subject: |
|
|
Perhaps you did not notice the inner loop in my example operates on each folder iterated by the outer loop. It is a trivial, functional equivalant of:
| Code: | loop, %A_AppData%\.purple\logs\aim\*\randomsn\*.html
| The same could be done for your example, with a loop for /home/*, and an inner loop for /home/whatever/public_html.
| Quote: | | That's totally different to standard Windows globbing as provided via the Loop, FilePattern routine of AHK. | It is merely a convenience; the loop or command is recursing for each wildcard, instead of requiring the programmer to do so explicitly. |
|
| Back to top |
|
 |
LBJ
Joined: 03 May 2007 Posts: 16
|
Posted: Sat Mar 08, 2008 1:19 pm Post subject: |
|
|
| lexiKos wrote: | | It is merely a convenience; the loop or command is recursing for each wildcard, instead of requiring the programmer to do so explicitly. |
Yes, I follow what you're saying and what you coded, but you basically made the case for globbing with your last comment.
Obviously a solution can be custom coded for any situation, but *nix globbing makes it a quick one liner rather than a potentially deep nesting of directory parsing loops.
It's just another tool, albeit a very powerful one. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2472 Location: Australia, Qld
|
Posted: Sat Mar 08, 2008 1:55 pm Post subject: |
|
|
What I didn't say is it's only of benefit if you specifically have a use for it. I don't. Thinking about it, though, I can understand how much better it would be for someone that has a need for it.
I think I mainly posted because xx3nvyxx's solution seemed overcomplicated, as does yours. Here is my crack at it:
| Code: | Glob(list, "C:\Program Files\?u*y\*\*.exe")
MsgBox %list%
Glob(ByRef list, Pattern, IncludeDirs=0)
{
if (i:=RegExMatch(Pattern,"[*?]")) && (i:=InStr(Pattern,"\",1,i+1))
Loop, % SubStr(Pattern, 1, i-1), 2
Glob(list, A_LoopFileLongPath . SubStr(Pattern,i), IncludeDirs)
else
Loop, %Pattern%, %IncludeDirs%
list .= (list="" ? "" : "`n") . A_LoopFileLongPath
} | It seems too simple... maybe I missed something?  |
|
| Back to top |
|
 |
xx3nvyxx
Joined: 05 Sep 2005 Posts: 86 Location: Down the hall, on your left.
|
Posted: Sat Mar 08, 2008 5:37 pm Post subject: |
|
|
...So how short is this function going to get?
I think everyone here has already completely shown me up. Which is, don't get me wrong, a very good thing. But I still would like to see this functionality added to ahk itself... _________________ Now the world has gone to bed,
Darkness won't engulf my head,
I can see by infra-red,
How I hate the night.
Now I lay me down to sleep,
Try to count electric sheep,
Sweet dream wishes you can keep,
How I hate the night. |
|
| Back to top |
|
 |
LBJ
Joined: 03 May 2007 Posts: 16
|
Posted: Sun Mar 09, 2008 12:31 am Post subject: |
|
|
| lexiKos wrote: | It seems too simple... maybe I missed something?  |
Not at all! That's a perfectly elegant solution.
| lexiKos wrote: | | What I didn't say is it's only of benefit if you specifically have a use for it. I don't. Thinking about it, though, I can understand how much better it would be for someone that has a need for it. |
Yes, as I said, it's just another useful tool, but it can be *very* useful. |
|
| Back to top |
|
 |
LBJ
Joined: 03 May 2007 Posts: 16
|
Posted: Tue Mar 11, 2008 4:21 am Post subject: |
|
|
| xx3nvyxx wrote: | | ...So how short is this function going to get? |
I doubt it will get much shorter, but building on the excellent solution of lexiKos, the line...
if (i:=RegExMatch(Pattern,"[*?]")) && (i:=InStr(Pattern,"\",1,i+1))
...can be simplified to a single RegExMatch as per...
if (i:=RegExMatch(Pattern,"(?<=[*?])\\"))
...giving...
| Code: | Glob(list, "C:\Program Files\*\*\*.exe")
MsgBox %list%
Glob(ByRef list, Pattern, IncludeDirs=0)
{
if (i:=RegExMatch(Pattern,"(?<=[*?])\\"))
Loop, % SubStr(Pattern, 1, i-1), 2
Glob(list, A_LoopFileLongPath . SubStr(Pattern,i), IncludeDirs)
else
Loop, %Pattern%, %IncludeDirs%
list .= (list="" ? "" : "`n") . A_LoopFileLongPath
} |
| xx3nvyxx wrote: | | But I still would like to see this functionality added to ahk itself... |
Yes, I definitely agree. I can't see a downside to its inclusion. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2472 Location: Australia, Qld
|
Posted: Tue Mar 11, 2008 6:34 am Post subject: |
|
|
| LBJ wrote: | | if (i:=RegExMatch(Pattern,"(?<=[*?])\\")) | That would allow wildcards only at the end of the name. Notice the pattern I used in my test: ?u*y.
Since look-behinds do not support quantifiers of varying size, the only way for it to work with a single regular expression would be to capture the string from [*?] to \\, and use an output variable to determine the position of the \.
Both methods perform roughly the same, but I see the InStr method as more intuitive. It also avoids an unnecessary variable... |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|