Walk a directory/Recursively: Difference between revisions
m
→{{header|Wren}}: Minor tidy
Simple9371 (talk | contribs) (Updated sample code...) |
m (→{{header|Wren}}: Minor tidy) |
||
(94 intermediate revisions by 49 users not shown) | |||
Line 1:
{{task|File System Operations}}
[[Category:Recursion]]
;Task:
Walk a given directory ''tree'' and print files matching a given pattern.
'''Note:''' This task is for recursive methods. These tasks should read an entire directory tree, not a ''single directory''.
'''Note:''' Please be careful when running any code examples found here.
;Related task:
* [[Walk a directory/Non-recursively]] (read a ''single directory'').
<br><br>
=={{header|11l}}==
{{trans|Nim}}
<syntaxhighlight lang="11l">L(filename) fs:walk_dir(‘/’)
I re:‘.*\.mp3’.match(filename)
print(filename)</syntaxhighlight>
=={{header|8th}}==
<
"*.c" f:rglob \ top of stack now has list of all "*.c" files, recursively
</syntaxhighlight>
=={{header|Ada}}==
<
with Ada.Text_IO;
Line 34 ⟶ 52:
begin
Walk (".", "*.adb");
end Test_Directory_Walk;</
The solution first enumerates files in a directory, that includes the subdirectories, if their names match the pattern. Then it steps down into each of the subdirectories. The pseudo directories . and .. are excluded. The behavior upon symbolic links depends on the [[OS]] and the implementation of the Ada.Directories package.
Line 41 ⟶ 59:
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386 - uses non-standard library routines ''get directory'' and'' grep in string''.}}
<!-- {{does not work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386 - ''get directory'' and'' grep in string'' not available in any library ... yet}} -->
<
STRING slash = "/", pwd=".", parent="..";
Line 67 ⟶ 85:
FI;
walk tree(".", match sort a68 and print)</
{{out|Sample output}}
<pre>
Line 82 ⟶ 100:
./Permutation_Sort.a68
</pre>
=={{header|Arturo}}==
<syntaxhighlight lang="rebol">; list all files at current path
print list.recursive "."
; get all files at given path
; and select only the ones we want
; just select the files with .md extension
select list.recursive "some/path"
=> [".md" = extract.extension]
; just select the files that contain "test"
select list.recursive "some/path"
=> [in? "test"]</syntaxhighlight>
=={{header|AutoHotkey}}==
Display all TMP files in Temp directory and its subdirectories.
<
out .= A_LoopFileName "`n"
MsgBox,% out</
=={{header|BaCon}}==
This line will recursively walk though all directories starting from the current directory ".":
<syntaxhighlight lang="qbasic">PRINT WALK$(".", 1, ".+", TRUE, NL$)</syntaxhighlight>
=={{header|Batch File}}==
A sample code that displays all the EXE files in System32 directory recursively.
<
----
If you wanted to apply some command to each item in a directory tree, then use <code>FOR</code> with the switch <code>/R</code>. For example, to apply the ECHO command to every DLL file in C:\Windows\System32:
{{works with|Windows NT|4 or later (includes Windows XP and onward)}}
<
This can be done from outside a batch file (entered directly at the command prompt) by changing the double percent signs (%%) to single percents (%):
<
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<
pattern$ = "*.chm"
PROClisttree(directory$, pattern$)
Line 128 ⟶ 166:
SYS "FindClose", sh%
ENDIF
ENDPROC</
=={{header|C}}==
==={{libheader|POSIX}}===
{{works with|POSIX|.1-2001}}
<
#include <sys/stat.h>
#include <unistd.h>
Line 235 ⟶ 273:
}
return 0;
}</
==={{libheader|BSD libc}}===
With the [http://www.openbsd.org/cgi-bin/man.cgi?query=fts&apropos=0&sektion=3&manpath=OpenBSD+Current&arch=i386&format=html fts(3)] functions from 4.4BSD, this program can sort the files, and can also detect cycles (when a link puts a directory inside itself). This program makes a ''logical traversal'' that follows symbolic links to directories.
{{works with|OpenBSD|4.9}}
<
#include <err.h>
#include <errno.h>
Line 322 ⟶ 360:
pmatch(".", "*.c");
return 0;
}</
=== [[Windows]] ===
{{libheader|Win32}}
{{works with|MinGW}}
<
#include <stdio.h>
#include <stdlib.h>
Line 563 ⟶ 601:
return 0;
}</
=={{header|C sharp|C#}}==
<
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace
{
class Program
{
static
{
while (directoryStack.Count > 0)
{
try
{
}
continue; // We don't have access to this directory, so skip it
}
foreach (var f in dir.GetFiles().Where(Pattern)) // "Pattern" is a function
}
}
static void Main(string[] args)
{
// Print the full path of all .wmv files that are somewhere in the C:\Windows directory or its subdirectories
foreach (var file in TraverseDirectory(@"C:\Windows", f => f.Extension == ".wmv"))
Console.WriteLine(file.FullName);
Console.WriteLine("Done.");
}
}
}
</syntaxhighlight>
=={{header|C++}}==
{{libheader|boost}}
<
#include "boost/regex.hpp"
#include <iostream>
Line 634 ⟶ 663:
std::cout << iter->path() << "\n";
}
}</
{{libheader|std|C++17}}
<syntaxhighlight lang="cpp">
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path current_dir(".");
// list all files containing an mp3 extension
for (auto &file : fs::recursive_directory_iterator(current_dir)) {
if (file.path().extension() == ".mp3")
std::cout << file.path().filename().string() << std::endl;
}
}</syntaxhighlight>
=={{header|Caché ObjectScript}}==
<
Class Utils.File [ Abstract ]
{
Line 661 ⟶ 706:
}
</syntaxhighlight>
{{out|Example}}
Line 677 ⟶ 722:
C:\Swsetup\Monitors\HP_w2207_3.0\Readme.txt
</pre>
=={{header|Clojure}}==
The standard function ''file-seq'' does a tree walk.
<syntaxhighlight lang="clojure">(use '[clojure.java.io])
(defn walk [dirpath pattern]
(doall (filter #(re-matches pattern (.getName %))
(file-seq (file dirpath)))))
(map #(println (.getPath %)) (walk "src" #".*\.clj"))
</syntaxhighlight>
=={{header|CoffeeScript}}==
{{works with|node.js}}
<
walk = (dir, f_match, f_visit) ->
Line 696 ⟶ 752:
matcher = (fn) -> fn.match /\.coffee/
action = console.log
walk dir, matcher, action</
=={{header|Common Lisp}}==
{{libheader|CL-FAD}}
This example uses the <code>CL-FAD</code> library to achieve compatibility where the ANSI CL standard leaves ambiguities about pathnames. Quicklisp is used to ensure it is loaded. Traversal is depth-first unless <code>:depth-first-p nil</code> is passed.
<syntaxhighlight lang="lisp">(ql:quickload :cl-fad)
(defun mapc-directory-tree (fn directory &key (depth-first-p t))
(dolist (entry (cl-fad:list-directory directory))
(unless depth-first-p
(funcall fn entry))
(when (cl-fad:directory-pathname-p entry)
(mapc-directory-tree fn entry))
(when depth-first-p
(funcall fn entry))))
</syntaxhighlight>
<
(when (equal (pathname-type x) "lisp")
(write-line (namestring x))))
Line 716 ⟶ 777:
/home/sthalik/lang/lisp/box-muller.lisp
/home/sthalik/lang/lisp/displaced-subseq.lisp
[...]</
=={{header|D}}==
<
import std.stdio, std.file;
Line 736 ⟶ 786:
// a depth-first scan):
dirEntries("", "*.d", SpanMode.breadth).writeln;
}</
=={{header|Dart}}==
<syntaxhighlight lang="dart">
import 'dart:io' show Directory, Platform, File;
void main(List<String> args) {
var dir = Directory(args[0]);
dir.list(recursive: true, followLinks: false).forEach((final cur) {
if (cur is Directory) {
print("Directory: ${cur.path}");
}
if (cur is File) {
print("File: ${cur.path}");
}
});
}
</syntaxhighlight>
=={{header|Delphi}}==
{{libheader| System.IOUtils}}
<syntaxhighlight lang="delphi">
program Walk_a_directory;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.IOUtils;
var
Files: TArray<string>;
FileName, Directory: string;
begin
Directory := TDirectory.GetCurrentDirectory; // dir = '.', work to
Files := TDirectory.GetFiles(Directory, '*.*', TSearchOption.soAllDirectories);
for FileName in Files do
begin
Writeln(FileName);
end;
Readln;
end.
</syntaxhighlight>
=={{header|E}}==
<
for name => file in directory {
if (name =~ rx`.*$pattern.*`) {
Line 748 ⟶ 844:
}
}
}</
{{out|Example}}
<
/usr/share/man/man1/rmdir.1
/usr/share/man/man2/rmdir.2</
=={{header|
<syntaxhighlight lang="elixir">defmodule Walk_directory do
def recursive(dir \\ ".") do
Enum.each(File.ls!(dir), fn file ->
IO.puts fname = "#{dir}/#{file}"
if File.dir?(fname), do: recursive(fname)
end)
end
end
Walk_directory.recursive</syntaxhighlight>
{{out}}
<pre>
./check.exs
./e.bat
./foo
./foo/bar
./foo/bar/1
./foo/bar/2
./foo/bar/a
./foo/bar/b
./input.txt
./test.beam
./test.exs
./test.txt
</pre>
=={{header|Emacs Lisp}}==
<syntaxhighlight lang="lisp">ELISP> (directory-files-recursively "/tmp/el" "\\.el$")
("/tmp/el/1/c.el" "/tmp/el/a.el" "/tmp/el/b.el")</syntaxhighlight>
=={{header|Erlang}}==
Use the builtin function [http://erlang.org/doc/man/filelib.html#fold_files-5 filelib:fold_files/5].
{{out}}
<syntaxhighlight lang="erlang">
walk_dir(Path, Pattern) ->
filelib:fold_files(
Path,
Pattern,
true, % Recurse
fun(File, Accumulator) -> [File|Accumulator] end,
[]
)
</syntaxhighlight>
<syntaxhighlight lang="erlang">
% Collect every file in the current directory
walkdir:walk_dir(".", ".*").
% Collect every file my .config folder that ends with `rc`
walkdir:walk_dir("/home/me/.config/", ".*rc$").
</syntaxhighlight>
=={{header|F_Sharp|F#}}==
This code is tail-recursive and lazy.
<
let rec getAllFiles dir pattern =
Line 777 ⟶ 915:
getAllFiles "c:\\temp" "*.xml"
|> Seq.iter (printfn "%s")</
=={{header|Factor}}==
<
"." t [
dup ".factor" tail? [ print ] [ drop ] if
] each-file</
=={{header|Forth}}==
{{works with|gforth|0.
<syntaxhighlight lang="forth">
require unix/filestat.fs
require unix/libc.fs
: $append ( from len to -- ) 2DUP >R >R COUNT + SWAP MOVE R> R@ C@ + R> C! ;
defer ls-filter
: dots? ( name len -- ? ) drop c@ [char] . = ;
file-stat buffer: statbuf
: isdir ( addr u -- flag )
statbuf lstat ?ior statbuf st_mode w@ S_IFMT and S_IFDIR = ;
: (ls-r) ( dir len -- )
pad c@ >r pad $append s" /" pad $append
pad count open-dir if drop r> pad c! exit then ( dirid)
begin
dup pad count + 256 rot read-dir throw
while
pad count + over dots? 0= if \ ignore
dup pad
isdir if
pad count + swap recurse
else drop then
else drop then
repeat
drop
close-dir throw
;
:
: c-files ( str len -- ? )
dup 3 < if 2drop false exit then
+ 1- dup c@ 32 or
Line 816 ⟶ 968:
1- dup c@ [char] . <> if drop false exit then
drop true ;
' c-
: all-files ( str len -- ? ) 2drop true ;
' all-files is ls-filter
s" ." ls-r cr
</syntaxhighlight>
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">#include "dir.bi"
Sub listFiles(Byref filespec As String, Byval attrib As Integer)
Dim As Integer count = 0
Dim As String filename = Dir(filespec, attrib)
Do While Len(filename) > 0
count += 1
Print filename
filename = Dir()
Loop
Print !"\nArchives count:"; count
End Sub
Dim As String mylist = "C:\FreeBASIC\""
Print "Directories:"
listFiles(mylist & "*", fbDirectory)
Print
Print "Archive files:"
listFiles(mylist & "*", fbArchive)
Sleep</syntaxhighlight>
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
include "NSLog.incl"
void local fn EnumerateDirectoryAtURL( dirURL as CFURLRef )
NSDirectoryEnumerationOptions options = NSDirectoryEnumerationSkipsPackageDescendants + ¬
NSDirectoryEnumerationSkipsHiddenFiles
DirectoryEnumeratorRef enumerator = fn FileManagerEnumeratorAtURL( dirURL, NULL, options, NULL, NULL )
CFURLRef url = fn EnumeratorNextObject( enumerator )
while ( url )
if ( fn StringIsEqual( fn URLPathExtension( url ), @"fb" ) )
NSLog(@"%@",url)
end if
url = fn EnumeratorNextObject( enumerator )
wend
end fn
fn EnumerateDirectoryAtURL( fn FileManagerURLForDirectory( NSDesktopDirectory, NSUserDomainMask ) )
HandleEvents
</syntaxhighlight>
=={{header|Gambas}}==
'''[https://gambas-playground.proko.eu/?gist=f48f8d5c2e2e85a8f80bcdc0124a35a5 Click this link to run this code]'''
<syntaxhighlight lang="gambas">Public Sub Main()
Dim sTemp As String
For Each sTemp In RDir("/etc", "*.d")
Print sTemp
Next
End</syntaxhighlight>
Output:
<pre>
sysctl.d
systemd/ntp-units.d
pam.d
security/limits.d
security/namespace.d
insserv.conf.d
udev/hwdb.d
....
</pre>
=={{header|GAP}}==
<
local dir, file, e;
dir := Directory(name);
Line 837 ⟶ 1,061:
# This will print filenames
Walk(".", Display);</
=={{header|Go}}==
<
import (
Line 853 ⟶ 1,077:
return nil // but continue walking elsewhere
}
if
return nil // not a file. ignore.
}
Line 869 ⟶ 1,093:
func main() {
filepath.Walk("/", VisitFile)
}</
=={{header|Groovy}}==
<syntaxhighlight lang="groovy">new File('.').eachFileRecurse {
if (it.name =~ /.*\.txt/) println it;
}</
Shorter variant:
<syntaxhighlight lang="groovy">new File('.').eachFileRecurse ~/.*\.txt/, { println it }</syntaxhighlight>
Variant processing only files:
<syntaxhighlight lang="groovy">new File('.').eachFileRecurse FILES, ~/.*\.txt/, { println it }</syntaxhighlight>
Flexible search, traversal can be adapted by providing various options in the options Map, see documentation of method:
[http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.html#traverse(java.util.Map,%20groovy.lang.Closure) traverse(Map options, Closure closure)]
<syntaxhighlight lang="groovy">new File('.').traverse(
type : FILES,
nameFilter : ~/.*\.txt/,
preDir : { if (it.name == '.svn') return SKIP_SUBTREE },
) { println it }
</syntaxhighlight>
=={{header|GUISS}}==
Here we list all files that match the pattern m*.txt in "My Documents" and all of its subfolders:
<
Inputbox: filename>m*.txt,Button:Search</
=={{header|Haskell}}==
Using the packages [http://hackage.haskell.org/package/directory-1.2.5.0/docs/System-Directory.html#v:getCurrentDirectory directory] and [https://hackage.haskell.org/package/filemanip-0.3.6.3/docs/System-FilePath-Find.html#v:find filemanip]
<syntaxhighlight lang="haskell">import System.Environment
import System.Directory
import System.FilePath.Find
search pat
main = do
[pat] <- getArgs
dir <- getCurrentDirectory
files <- search pat dir
mapM_ putStrLn files</syntaxhighlight>
or more classic way:
<syntaxhighlight lang="haskell">import System.FilePath.Posix
import System.Directory
import System.IO
dirWalk :: (FilePath -> IO ()) -> FilePath -> IO ()
dirWalk filefunc top = do
isDirectory <- doesDirectoryExist top
if isDirectory
then do
files <- listDirectory top
mapM_ (dirWalk filefunc . (top </>)) files
else filefunc top
main :: IO ()
main = do
hSetEncoding stdout utf8
hSetEncoding stdin utf8
let worker fname
| takeExtension fname == ".hs" = putStrLn fname
| otherwise = return ()
dirWalk worker "."</syntaxhighlight>
== Icon and Unicon ==
Line 903 ⟶ 1,164:
Icon doesn't support 'stat' or 'open' of a directory; however, information can be obtained by use of the <code>system</code> function to access command line.
==={{header|Unicon}}===
<syntaxhighlight lang="unicon">
###########################
# A sequential solution #
Line 976 ⟶ 1,237:
return D
}
end</
=={{header|IDL}}==
<syntaxhighlight lang="idl">result = file_search( directory, '*.txt', count=cc )</syntaxhighlight>
This will descend down the directory/ies in the variable <tt>"directory"</tt> (which can be an array) returning an array of strings with the names of the files matching "*.txt" and placing the total number of matches into the variable <tt>"cc"</tt>
=={{header|J}}==
<
>{."1 dirtree '*.html'</
The verb <tt>dirtree</tt> returns a file listing of a directory tree as a boxed matrix with file names in the first column. The primitives <tt>>{."1</tt> will return the unboxed contents of the first column.
Line 989 ⟶ 1,254:
{{works with|Java|1.4+}}
Done using no pattern. But with end string comparison which gave better results.
<
public class MainEntry {
Line 1,017 ⟶ 1,282:
}
}
}</
{{works with|Java|7+}}
Luckily, <code>java.nio.file.Files</code> gives us a <code>walkFileTree</code> method that does exactly what this task calls for.
<
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
Line 1,038 ⟶ 1,303:
});
}
}</
{{works with|Java|8+}}
<
import java.nio.file.*;
Line 1,052 ⟶ 1,317:
}
}
</syntaxhighlight>
=={{header|JavaScript}}==
{{works with|JScript}}
<
function walkDirectoryTree(folder, folder_name, re_pattern) {
Line 1,085 ⟶ 1,350:
}
walkDirectoryTree(dir, dir.name, '\\.txt$');</
=={{header|Julia}}==
{{works with|Julia|1.2}}
<syntaxhighlight lang="julia">rootpath = "/home/user/music"
pattern = r".mp3$"
for (root, dirs, files) in walkdir(rootpath)
for file in files
if occursin(pattern, file) println(file) end
end
end</syntaxhighlight>
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.2.0
import java.io.File
fun walkDirectoryRecursively(dirPath: String, pattern: Regex): Sequence<String> {
val d = File(dirPath)
require (d.exists() && d.isDirectory())
return d.walk().map { it.name }.filter { it.matches(pattern) }.sorted().distinct() }
fun main(args: Array<String>) {
val r = Regex("""^v(a|f).*\.h$""") // get all C header files beginning with 'va' or 'vf'
val files = walkDirectoryRecursively("/usr/include", r)
for (file in files) println(file)
}
</syntaxhighlight>
Output (Ubuntu 14.04):
<pre>
valarray_after.h
valarray_array.h
valarray_before.h
values.h
vfio.h
vfs.h
</pre>
=={{header|Lasso}}==
<
define dir -> eachVisibleFilePath() => {
return with name in self -> eachEntry where #name -> second != io_dir_dt_dir where not(#name -> first -> beginswith('.')) select .makeFullPath(#name -> first)
Line 1,118 ⟶ 1,421:
do #matchingfilenames -> insert(#filename)
#matchingfilenames</
-> array(myfile.lasso, test.lasso, rosetta.lasso)
=={{header|
<syntaxhighlight lang="livecode">function pathsForDirectoryAndWildcardPattern pDirectory, pWildcardPattern
-- returns a return-delimited list of long file names
-- the last character in the list is a return, unless the list is empty
filter files(pDirectory) with pWildcardPattern
repeat for each line tFile in it
put pDirectory & slash & tFile & cr after tPaths
end repeat
filter folders(pDirectory) without ".."
repeat for each line tFolder in it
put pathsForDirectoryAndWildcardPattern(pDirectory & slash & tFolder, pWildcardPattern) after tPaths
end repeat
return tPaths
end pathsForDirectoryAndWildcardPattern</syntaxhighlight>
Example
<syntaxhighlight lang="livecode">put pathsForDirectoryAndWildcardPattern(the documents folder, "*.livecode*"</syntaxhighlight>
Output
<pre>...
/Users/xxx/Documents/abc.livecode
/Users/xxx/Documents/def.livecodescript
...</pre>
<nowiki>--~~~~</nowiki>
=={{header|Lua}}==
Lua itself is extremely spartanic as it is meant for embedding. As lfs (LuaFileSystem) is about as standard an extension as it gets, we use that.
<syntaxhighlight lang="lua">local lfs = require("lfs")
-- This function takes two arguments:
-- - the directory to walk recursively;
-- - an optional function that takes a file name as argument, and returns a boolean.
function find(self, fn)
return coroutine.wrap(function()
for f in lfs.dir(self) do
if f ~= "." and f ~= ".." then
local _f = self .. "/" .. f
if not fn or fn(_f) then
coroutine.yield(_f)
end
if lfs.attributes(_f, "mode") == "directory" then
for n in find(_f, fn) do
coroutine.yield(n)
end
end
end
end
end)
end
-- Examples
-- List all files and directories
for f in find("directory") do
print(f)
end
-- List lua files
for f in find("directory", function(self) return self:match("%.lua$") end) do
print(f)
end
-- List directories
for f in find("directory", function(self) return "directory" == lfs.attributes(self, "mode") end) do
print(f)
end</syntaxhighlight>
Lua provides functions such as os.execute([command]) and io.popen(prog [, mode]). Below an example for Windows users having io.popen at their disposal. Mind you, it may pop-up a command window.
<syntaxhighlight lang="lua">-- Gets the output of given program as string
-- Note that io.popen is not available on all platforms
local function getOutput(prog)
local file = assert(io.popen(prog, "r"))
local output = assert(file:read("*a"))
file:close()
return output
end
-- Iterates files in given directory
local function files(directory, recursively)
-- Use windows" dir command
local directory = directory:gsub("/", "\\")
local filenames = getOutput(string.format("dir %s %s/B/A:A", directory, recursively and '/S' or ''))
-- Function to be called in "for filename in files(directory)"
return coroutine.wrap(function()
for filename in filenames:gmatch("([^\r\n]+)") do
coroutine.yield(filename)
end
end)
end
-- Walk "C:/Windows" looking for executables
local directory = "C:/Windows"
local pattern = ".*%.exe$" -- for finding executables
for filename in files(directory, true) do
if filename:match(pattern) then
print(filename)
end
end</syntaxhighlight>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
The built-in function <code>FileNames</code> does exactly this:
:<code>FileNames[]</code> lists all files in the current working directory.
Line 1,129 ⟶ 1,533:
:<code>FileNames[forms,dirs,n]</code> includes files that are in subdirectories up to n levels down.
Examples (find all files in current directory, find all png files in root directory, find all files on the hard drive):
<
FileNames["*.png", $RootDirectory]
FileNames["*", {"*"}, Infinity]</
the result can be printed with Print /@ FileNames[....]
=={{header|MATLAB}} / {{header|Octave}}==
<
f = dir(fullfile(d,pattern));
for k = 1:length(f)
end;
Line 1,148 ⟶ 1,552:
end;
end;
end; </
=={{header|MAXScript}}==
<
(
dirArr = GetDirectories (dir + "\\*")
Line 1,168 ⟶ 1,572:
)
walkDir "C:" "*.txt"</
=={{header|MoonScript}}==
MoonScript compiles to Lua, which itself is extremely spartanic as it is meant for embedding. As lfs (LuaFileSystem) is about as standard an extension as it gets, we use that.
<syntaxhighlight lang="moonscript">lfs = require "lfs"
-- This function takes two arguments:
-- - the directory to walk recursively;
-- - an optional function that takes a file name as argument, and returns a boolean.
find = (fn) => coroutine.wrap ->
for f in lfs.dir @
if f ~= "." and f ~= ".."
_f = @.."/"..f
coroutine.yield _f if not fn or fn _f
if lfs.attributes(_f, "mode") == "directory"
coroutine.yield n for n in find _f, fn
-- Examples
-- List all files
print f for f in find "templates"
-- List moonscript files
print f for f in find "templates", => @\match "%.moon$"
-- List directories
print f for f in find "templates", => "directory" == lfs.attributes @, "mode"</syntaxhighlight>
=={{header|Nanoquery}}==
<syntaxhighlight lang="nanoquery">import Nanoquery.IO
def get_files(dirname)
local_filenames = new(File).listDir(dirname)
filenames = {}
for i in range(0, len(local_filenames) - 1)
if len(local_filenames) > 0
if not new(File, local_filenames[i]).isDir()
filenames.append(local_filenames[i])
else
filenames += get_files(local_filenames[i])
end
end
end
return filenames
end
f = new(File)
for file in get_files("/")
if lower(f.getExtension(file)) = ".mp3"
println file
end
end</syntaxhighlight>
=={{header|Nim}}==
The “os” standard module provides an iterator to walk recursively a directory. The iterator allows some filtering about the kind of entry to consider: real files (default), symbolic links to files, directories, symbolic links to directories. It doesn’t allow to specify a pattern, so filtering on name should be done using another mechanism (for instance, regular expressions).
<syntaxhighlight lang="nim">import os, re
for file in walkDirRec "/":
if file.match re".*\.mp3":
echo file</
=={{header|Objeck}}==
<syntaxhighlight lang="objeck">use System.IO.File;
class Test {
function : Main(args : String[]) ~ Nil {
if(args->Size() = 2) {
DescendDir(args[0], args[1]);
};
}
function : DescendDir(path : String, pattern : String) ~ Nil {
files := Directory->List(path);
each(i : files) {
file := files[i];
if(<>file->StartsWith('.')) {
dir_path := String->New(path);
dir_path += '/';
dir_path += file;
if(Directory->Exists(dir_path)) {
DescendDir(dir_path, pattern);
}
else if(File->Exists(dir_path) & dir_path->EndsWith(pattern)) {
dir_path->PrintLine();
};
};
};
}
}</syntaxhighlight>
=={{header|Objective-C}}==
<
NSDirectoryEnumerator *de = [[NSFileManager defaultManager] enumeratorAtPath:dir];
for (NSString *file in de)
if ([[file pathExtension] isEqualToString:@"mp3"])
NSLog(@"%@", file);</
=={{header|OCaml}}==
<
#load "unix.cma"
#load "str.cma"
Line 1,192 ⟶ 1,682:
let walk_directory_tree dir pattern =
let
let select str = Str.string_match re str 0 in
let rec walk acc = function
| [] -> (acc)
Line 1,215 ⟶ 1,706:
let results = walk_directory_tree "/usr/local/lib/ocaml" ".*\\.cma" in
List.iter print_endline results;
;;</
=={{header|ooRexx}}==
===version 1===
<
* List all file names on my disk D: that contain the string TTTT
*--------------------------------------------------------------------*/
Line 1,228 ⟶ 1,719:
If pos('TTTT',translate(file.i))>0 Then
say file.i
end</
{{out}}
<pre>1127869 files on disk
Line 1,236 ⟶ 1,727:
===version 2===
Get only files matching the file-spec.
<
* List all file names on my disk D: that contain the string TTTT
*--------------------------------------------------------------------*/
Line 1,245 ⟶ 1,736:
If pos('TTTT',translate(file.i))>0 Then
say file.i
end </
{{out}}
<pre>3 files found
Line 1,253 ⟶ 1,744:
=={{header|Oz}}==
<
[Path] = {Module.link ['x-oz://system/os/Path.ozf']}
[Regex] = {Module.link ['x-oz://contrib/regex']}
Line 1,271 ⟶ 1,762:
end
in
{WalkDirTree "." ".*\\.oz$" System.showInfo}</
=={{header|Perl}}==
Use the <tt>File::Find</tt> module from CPAN:
{{works with|Perl|5.x}}
<
my $dir = '.';
my $pattern = 'foo';
find $callback, $dir;</syntaxhighlight>
Or if you need maximum performance and are on a 'nix system, open a pipe to the GNU <tt>find</tt> program:
<syntaxhighlight lang="perl">sub shellquote { "'".(shift =~ s/'/'\\''/gr). "'" }
sub find_files {
my $dir = shellquote(shift);
my $test = shellquote(shift);
local $/ = "\0";
open my $pipe, "find $dir -iname $test -print0 |" or die "find: $!.\n";
while (<$pipe>) { print "$_\n"; } # Here you could do something else with each file path, other than simply printing it.
close $pipe;
}
find_files('.', '*.mp3');</syntaxhighlight>
Or using the recently popular Path::Tiny
<syntaxhighlight lang="perl">#!/usr/bin/perl
use strict; # https://rosettacode.org/wiki/Walk_a_directory/Recursively
use warnings;
use Path::Tiny;
path('.')->visit( sub {/\.c$/ and print "$_\n"}, {recurse => 1} );</syntaxhighlight>
=={{header|Phix}}==
{{libheader|Phix/basics}}
There is a builtin routine for this, walk_dir() - if interested you can find the full implementation in builtins\file.e (an autoinclude).
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">function</span> <span style="color: #000000;">find_pfile</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">pathname</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">dirent</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"pfile.e"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dirent</span><span style="color: #0000FF;">[</span><span style="color: #000000;">D_NAME</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- return pathname&dirent[D_NAME] -- as below</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">pathname</span><span style="color: #0000FF;">&</span><span style="color: #008000;">"\\"</span><span style="color: #0000FF;">&</span><span style="color: #000000;">dirent</span><span style="color: #0000FF;">[</span><span style="color: #000000;">D_NAME</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- non-zero terminates scan</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">walk_dir</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"C:\\Program Files (x86)\\Phix"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">find_pfile</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
Passing 1 as the third parameter makes it scan recursively.
{{out}}
<pre>
"C:\\Program Files (x86)\\Phix\\.hg\\store\\data\\builtins\\pfile.e.i"
"C:\\Program Files (x86)\\Phix\\builtins\\pfile.e"
0
</pre>
<small>[the final 0 is from the walk_dir() call, whereas both paths are printed from inside find_pfile()]</small>
=={{header|PHP}}==
<
$prefix = $dir . '/';
$dir = dir($dir);
Line 1,299 ⟶ 1,839:
}
}
findFiles('./foo', '/\.bar$/');</
This implementation uses Perl compatible regular expressions to match the whole path of the file
===PHP BFS (Breadth First Search)===
<syntaxhighlight lang="php">/*
This script performs a BFS search with recursion protection
it is often faster to search using this method across a
Line 1,391 ⟶ 1,931:
}
closedir($dh);
}</
=={{header|PicoLisp}}==
<
(recur (Dir)
(for F (dir Dir)
Line 1,402 ⟶ 1,942:
(recurse Path) ) # Yes: Recurse
((match '`(chop "s@.l") (chop F)) # Matches 's*.l'?
(println Path) ) ) ) ) ) ) # Yes: Print it</
{{out}}
<pre>"./src64/sym.l"
Line 1,410 ⟶ 1,950:
=={{header|Pop11}}==
Built-in procedure <code>sys_file_match</code> searches directories or directory trees using shell-like patterns (three dots indicate search for subdirectory tree).
<
;;; create path repeater
sys_file_match('.../*.p', '', false, 0) -> repp;
Line 1,417 ⟶ 1,957:
;;; print the path
printf(fil, '%s\n');
endwhile;</
=={{header|PowerShell}}==
In PowerShell the <code>Get-ChildItem</code> cmdlet allows for recursive filtering on file names with simple wildcards:
<
For more complex filtering criteria the result of <code>Get-ChildItem</code> can be piped into the <code>Where-Object</code> cmdlet:
<
Where-Object { $_.Name -match 'foo[0-9]' -and $_.Length -gt 5MB }</
To perform an action on every matching file the results can be piped into the <code>ForEach-Object</code> cmdlet:
<
Where-Object { $_.Name -match 'foo[0-9]' } |
ForEach-Object { ... }</
''Note:'' To include only ''files'' instead of directories too each of the above needs an additional<code>Where-Object</code> filter:
<
=={{header|Prolog}}==
{{works with|Swi-Prolog|8.3}}
<syntaxhighlight lang="prolog">
% submitted by Aykayayciti (Earl Lamont Montgomery)
% altered from fsaenzperez April 2019
% (swi-prolog.discourse-group)
test_run :-
proc_dir('C:\\vvvv\\vvvv_beta_39_x64').
proc_dir(Directory) :-
format('Directory: ~w~n',[Directory]),
directory_files(Directory,Files),!, %cut inserted
proc_files(Directory,Files).
proc_files(Directory, [File|Files]) :-
proc_file(Directory, File),!, %cut inserted
proc_files(Directory, Files).
proc_files(_Directory, []).
proc_file(Directory, File) :-
(
File = '.',
directory_file_path(Directory, File, Path),
exists_directory(Path),!,%cut inserted
format('Directory: ~w~n',[File])
;
File = '..',
directory_file_path(Directory, File, Path),
exists_directory(Path),!,%cut inserted
format('Directory: ~w~n',[File])
;
directory_file_path(Directory, File, Path),
exists_directory(Path),!,%cut inserted
proc_dir(Path)
;
directory_file_path(Directory, File, Path),
exists_file(Path),!,%cut inserted
format('File: ~w~n',[File])
;
format('Unknown: ~w~n',[File])
).</syntaxhighlight>
output :
<syntaxhighlight lang="prolog">?- test_run.
File: GMFBridge.ax
File: libeay32.dll
File: ssleay32.dll
File: license.txt
Directory: C:\vvvv\vvvv_beta_39_x64/licenses
Directory: .
Directory: ..
File: Apache.txt
File: BSD.txt
File: LGPL.txt
File: MIT.txt
File: MPL.txt
File: MS-PL-Eula.rtf
File: MS-PL.txt
File: MSR-SSLA.txt
</syntaxhighlight>
=={{header|PureBasic}}==
<
Static RegularExpression
If Not RegularExpression
Line 1,455 ⟶ 2,061:
EndIf
Wend
EndProcedure</
<
ExamineDirectory(1,"C:\WINDOWS\","")
WalkRecursive(1,"C:\WINDOWS\","\.log$")
FinishDirectory(1)</
=={{header|Prolog}}==
{{works with|Swi-Prolog|8.3}}
<syntaxhighlight lang="prolog">% submitted by Aykayayciti (Earl Lamont Montgomery)
% altered from fsaenzperez April 2019
% (swi-prolog.discourse-group)
test_run :-
proc_dir('C:\\vvvv\\vvvv_beta_39_x64').
proc_dir(Directory) :-
format('Directory: ~w~n',[Directory]),
directory_files(Directory,Files),!, %cut inserted
proc_files(Directory,Files).
proc_files(Directory, [File|Files]) :-
proc_file(Directory, File),!, %cut inserted
proc_files(Directory, Files).
proc_files(_Directory, []).
proc_file(Directory, File) :-
(
File = '.',
directory_file_path(Directory, File, Path),
exists_directory(Path),!,%cut inserted
format('Directory: ~w~n',[File])
;
File = '..',
directory_file_path(Directory, File, Path),
exists_directory(Path),!,%cut inserted
format('Directory: ~w~n',[File])
;
directory_file_path(Directory, File, Path),
exists_directory(Path),!,%cut inserted
proc_dir(Path)
;
directory_file_path(Directory, File, Path),
exists_file(Path),!,%cut inserted
format('File: ~w~n',[File])
;
format('Unknown: ~w~n',[File])
).</syntaxhighlight>
output :
<syntaxhighlight lang="prolog">?- test_run.
File: GMFBridge.ax
File: libeay32.dll
File: ssleay32.dll
File: license.txt
Directory: C:\vvvv\vvvv_beta_39_x64/licenses
Directory: .
Directory: ..
File: Apache.txt
File: BSD.txt
File: LGPL.txt
File: MIT.txt
File: MPL.txt
File: MS-PL-Eula.rtf
File: MS-PL.txt
File: MSR-SSLA.txt</syntaxhighlight>
=={{header|Python}}==
{{works with|Python|3.x}}
Use the standard [https://docs.python.org/3/library/pathlib.html#pathlib.Path.rglob pathlib.Path.rglob()] module to recursively walk a directory with optional filter.
<syntaxhighlight lang="python">
from pathlib import Path
for path in Path('.').rglob('*.*'):
print(path)
</syntaxhighlight>
{{works with|Python|3.x}}
{{works with|Python|2.3+}}
This uses the standard [http://docs.python.org/py3k/library/os.html?highlight=os.walk#os.walk os.walk()] module function to walk a directory tree, and the [http://docs.python.org/py3k/library/fnmatch.html fnmatch] module for matching file names.
<
import os
Line 1,473 ⟶ 2,151:
for root, dirs, files in os.walk(rootPath):
for filename in fnmatch.filter(files, pattern):
print( os.path.join(root, filename))</
{{works with|Python|<nowiki>2.x</nowiki>}}
{{works with|Python|<nowiki>3.x</nowiki>}}
A more strictly comparable port of this 2.3+ code to earlier versions of Python would be:
<
import os, os.path
Line 1,485 ⟶ 2,163:
print os.path.join(dir, filename)
os.path.walk('/', print_fnmatches, '*.mp3')</
The old ''os.path.walk'' function was a challenge for many to use because of the need to pass a function into the walk, and any arguments to that function through to it ... as shown. It's sometimes useful to pass mutable objects (lists, dictionaries, or instances of user-defined classes) to the inner function ... for example, to collect all the matching files for later processing.
Line 1,492 ⟶ 2,170:
{{libheader|Path}}
(''Note:'' This uses a non-standard replacement to the '''os.path''' module)
<
rootPath = '/'
Line 1,499 ⟶ 2,177:
d = path(rootPath)
for f in d.walkfiles(pattern):
print f</
=={{header|R}}==
<
=={{header|Racket}}==
<syntaxhighlight lang="racket">
-> (for ([f (in-directory "/tmp")] #:when (regexp-match? "\\.rkt$" f))
(displayln f))
... *.rkt files including in nested directories ...
</syntaxhighlight>
=={{header|Raku}}==
(formerly Perl 6)
Using the [https://github.com/tadzik/File-Find/ File::Find] module:
<syntaxhighlight lang="raku" line>use File::Find;
.say for find dir => '.', name => /'.txt' $/;</syntaxhighlight>
Alternatively, a custom solution that provides the same interface as the built-in (non-recursive) <tt>dir</tt> function, and uses <tt>gather</tt>/<tt>take</tt> to return a lazy sequence:
<syntaxhighlight lang="raku" line>sub find-files ($dir, Mu :$test) {
gather for dir $dir -> $path {
if $path.basename ~~ $test { take $path }
if $path.d { .take for find-files $path, :$test };
}
}
.put for find-files '.', test => /'.txt' $/;</syntaxhighlight>
Or if you value performance over portability, here's a function that runs the GNU <tt>find</tt> program and returns a lazy sequence of the files it finds. Parameters are not subjected to shell expansion, and the null-byte (which cannot be present in file paths) is used as the path delimiter, so it should be pretty safe.
<syntaxhighlight lang="raku" line>sub find-files ($dir, :$pattern) {
run('find', $dir, '-iname', $pattern, '-print0', :out, :nl«\0»).out.lines;
}
.say for find-files '.', pattern => '*.txt';</syntaxhighlight>
=={{header|Rascal}}==
<
module Walk
import String;
Line 1,523 ⟶ 2,228:
elseif (isDirectory(a+entry))
Walk(a+entry, pattern);
}</
=={{header|REALbasic}}==
<
For i As Integer = 1 To parentDir.Count
If parentDir.Item(i).Directory Then
Line 1,538 ⟶ 2,243:
End If
Next
End Sub</
Accepts a FolderItem object and a Regex pattern as a string:
<syntaxhighlight lang="vb">
Dim f As FolderItem = GetFolderItem("C:\Windows\system32")
Dim pattern As String = "((?:[a-z][a-z]+))(\.)(dll)" //all file names ending in .dll
printFiles(f, pattern)</
=={{header|Red}}==
<syntaxhighlight lang="red">Red []
walk: func [
"Walk a directory tree recursively, setting WORD to each file and evaluating BODY."
'word "For each file, set with the absolute file path."
directory [file!] "Starting directory."
body [block!] "Block to evaluate for each file, during which WORD is set."
/where
rules [block!] "Parse rules defining file names to include."
][
foreach file read directory [
if where [if not parse file rules [continue]]
either dir? file: rejoin [directory file] [walk item file body] [
set 'word file
do body
]
]
]
rules: compose [
any (charset [#"A" - #"Z"])
".TXT"
]
walk/where file %/home/user/ [print file] rules</syntaxhighlight>
=={{header|REXX}}==
===version 1===
{{works with|Regina}}
The following program was tested in a DOS window under Windows/XP and should work for all Microsoft Windows.
<
parse arg xdir; if xdir='' then xdir='\'
@.=0 /*default result in case ADDRESS fails.
trace off /*suppress REXX error message for fails*/
address system dirCmd xdir with output stem @. /*issue the DOS DIR command with option*/
if rc\==0 then do
say '
if #==0 then #=' no ' /*use a better word choice for 0 (zero)*/
say center('directory ' xdir " has " # ' matching entries.', 79, "─")
do j=1 for #; say @.j
end /*j*/
exit @.0+rc /*stick a fork in it, we're all done. */</
'''output''' when the following was used: <tt> I:\firefox*.exe </tt>
<pre>
─────────────directory I:\firefox*.exe has 6 matching entries.─────────────
I:\FIREFOX\firefox.exe
I:\FIREFOX\INSTALL\Firefox Setup 1.5.0.1.exe
I:\FIREFOX\INSTALL\Firefox Setup 2.0.0.4.exe
I:\FIREFOX\INSTALL\Firefox Setup 3.0.4.exe
I:\FIREFOX\INSTALL\Firefox Setup 3.6 Beta 5.exe
I:\FIREFOX\INSTALL\Firefox Setup 4.0 Beta 11.exe
</pre>
===version 2===
{{trans|BATCH-file}}
Works on Windows with ooRexx and Regina (not much REXX code in it)
<syntaxhighlight lang="rexx">'dir /s /b "%windir%\System32\*.exe"'</syntaxhighlight>
=={{header|Ring}}==
<syntaxhighlight lang="ring">
see "Testing DIR() " + nl
mylist = dir("C:\Ring")
for x in mylist
if x[2]
see "Directory : " + x[1] + nl
else
see "File : " + x[1] + nl
ok
next
see "Files count : " + len(mylist)
</syntaxhighlight>
Output:
<pre>
Testing DIR()
Directory : bert
Directory : bin
Directory : calmosoft
Directory : doc
Directory : FlappyBird
Directory : gameengine
Directory : html
Directory : images
File : License.txt
File : music1.wav
File : ReadMe.txt
Directory : ring-master
Directory : samples
Directory : StarsFighter
File : start.bat
Directory : stdlib
Directory : SuperMan2016
File : unixdict.txt
Directory : weblib
Files count : 19
</pre>
=={{header|Ruby}}==
Line 1,572 ⟶ 2,358:
Using the Find core Module:
<
Find.find('/your/path') do |f|
# print file and path to screen if filename ends in ".mp3"
puts f if f.match(/\.mp3\Z/)
end</
A little less verbose example using a shortcut for the glob method of Dir:
<
=={{header|Rust}}==
Using std::fs::walk_dir (unstable as of Rust 1.1) with imperative for-loop:
<syntaxhighlight lang="rust">#![feature(fs_walk)]
use std::fs;
use std::path::Path;
fn main() {
for f in fs::walk_dir(&Path::new("/home/pavel/Music")).unwrap() {
let p = f.unwrap().path();
if p.extension().unwrap_or("".as_ref()) == "mp3" {
println!("{:?}", p);
}
}
}</syntaxhighlight>
=={{header|Scala}}==
This is not implemented in the Scala library. Here is a simple solution, building on [[Java]] class ''<code>java.io.File</code>'':
<
object `package` {
Line 1,601 ⟶ 2,405:
for(f <- walkTree(dir)) println(f)
for(f <- walkTree(dir) if f.getName.endsWith(".mp3")) println(f)
}</
=={{header|Scheme}}==
Varies slightly depending on the implementation of scheme.
{{works with|Chicken Scheme}}
<
(use files)
(use srfi-13)
Line 1,621 ⟶ 2,425:
(FN MYPATH) )))) (directory PATH #t) ))
(walk (lambda (X) (cond ((string-suffix? ".scm" X) (display X)(newline) ))) "/home/user/")</
See also: '''(find-files ...)''' function in the '''posix''' module.
{{works with|Gauche}}
<
(use srfi-13)
Line 1,637 ⟶ 2,441:
(FN MYPATH) )))) (directory-list PATH :add-path? #t :children? #t ) ))
(walk (lambda (X) (cond ((string-suffix? ".scm" X) (display X)(newline) ))) "/home/user/")</
See also: '''(find-file-in-paths ...)''' function in the '''file.util''' module.
{{works with|PLT Scheme}}
<
(require srfi/13)
Line 1,655 ⟶ 2,459:
(FN MYPATH) )))) (directory-list PATH)))
(walk (lambda (X) (cond ((string-suffix? ".scm" (path->string X)) (display X)(newline) ))) "/home/user/")</
See also: '''(find-files ...)''' function in the '''file''' module.
{{out|Sample output}}
Line 1,673 ⟶ 2,477:
[http://seed7.sourceforge.net/libraries/osfiles.htm#fileType%28in_string%29 fileType].
<
include "osfiles.s7i";
Line 1,695 ⟶ 2,499:
begin
walkDir(".", ".sd7");
end func;</
=={{header|Sidef}}==
<syntaxhighlight lang
dir.open(\var dir_h) || return
dir_h.entries.each { |entry|
if (entry.is_a(Dir)) {
traverse(callback, entry)
} else {
callback(entry)
}
}
}
var dir = Dir.cwd
var pattern = /foo/
traverse(
{ |file|
if (file.basename ~~ pattern) {
say file
}
} => dir
)</syntaxhighlight>
=={{header|Smalltalk}}==
{{works with|GNU Smalltalk}}
<
wholeContent: aPattern do: twoBlock [
self wholeContent: aPattern withLevel: 0 do: twoBlock.
Line 1,748 ⟶ 2,552:
]
]
].</
<
d := Directory name: '.'.
d wholeContent: '\.st$' do: [ :f :l |
0 to: l do: [ :i | (Character tab) display ].
f displayNl
].</
=={{header|Swift}}==
{{works with|Swift|3.0}}
<syntaxhighlight lang="swift">import Foundation
let fileSystem = FileManager.default
let rootPath = "/"
// Enumerate the directory tree (which likely recurses internally)...
if let fsTree = fileSystem.enumerator(atPath: rootPath) {
while let fsNodeName = fsTree.nextObject() as? NSString {
let fullPath = "\(rootPath)/\(fsNodeName)"
var isDir: ObjCBool = false
fileSystem.fileExists(atPath: fullPath, isDirectory: &isDir)
if !isDir.boolValue && fsNodeName.pathExtension == "txt" {
print(fsNodeName)
}
}
}</syntaxhighlight>
=={{header|Tcl}}==
{{works with|Tcl|8.5}}
<
package require fileutil
proc walkin {path cmd} {
Line 1,791 ⟶ 2,619:
}
}}}
</syntaxhighlight>
=={{header|
There is more than one way to do this in TXR. A recursive walk could be coded using <code>open-directory</code> and <code>getline</code>. Or FFI could be used to gain access to some platform-specific functions like Microsoft's <code>FindFirstFile</code> and so forth.
===Using <code>ftw</code>===
TXR wraps and exposes the POSIX <code>nftw</code> function, which is demonstrated here. This function encapsulates a tree walk, and uses callbacks to inform the program of visited filesystem tree nodes, and of error situations. We can use a <code>lambda</code> for the code walk, or wrap the invocation of <code>ftw</code> with a macro which hides the <code>lambda</code> syntax.
Here we use the <code>build</code> macro for procedural list building to gather all of the found paths into a list, which is implicitly returned. The callback is an explicit <code>lambda</code>:
<syntaxhighlight lang="txrlisp">(build (ftw "." (lambda (path type stat level base)
(if (ends-with ".tl" path)
(add path)))))</syntaxhighlight>
{{out}}
<syntaxhighlight lang="txrlisp">("./tests/016/arith.tl" "./tests/014/dgram-stream.tl" "./tests/014/socket-basic.tl"
"./tests/sock-common.tl" "./tests/012/ifa.tl" "./tests/012/except.tl"
"./tests/012/fini.tl" "./tests/012/oop.tl" "./tests/012/circ.tl"
"./tests/012/cont.tl" "./tests/012/aseq.tl" "./tests/012/quasi.tl"
"./tests/012/struct.tl" "./tests/012/man-or-boy.tl" "./tests/017/glob-carray.tl"
"./tests/017/glob-zarray.tl" "./tests/017/realpath.tl" "./tests/017/qsort.tl"
"./tests/015/split.tl" "./tests/013/maze.tl" "./tests/common.tl"
"./tests/011/special-1.tl" "./share/txr/stdlib/ifa.tl" "./share/txr/stdlib/with-stream.tl"
"./share/txr/stdlib/pmac.tl" "./share/txr/stdlib/except.tl" "./share/txr/stdlib/awk.tl"
"./share/txr/stdlib/package.tl" "./share/txr/stdlib/place.tl"
"./share/txr/stdlib/trace.tl" "./share/txr/stdlib/type.tl" "./share/txr/stdlib/keyparams.tl"
"./share/txr/stdlib/ffi.tl" "./share/txr/stdlib/ver.tl" "./share/txr/stdlib/build.tl"
"./share/txr/stdlib/cadr.tl" "./share/txr/stdlib/hash.tl" "./share/txr/stdlib/error.tl"
"./share/txr/stdlib/txr-case.tl" "./share/txr/stdlib/tagbody.tl"
"./share/txr/stdlib/getopts.tl" "./share/txr/stdlib/socket.tl"
"./share/txr/stdlib/struct.tl" "./share/txr/stdlib/getput.tl"
"./share/txr/stdlib/path-test.tl" "./share/txr/stdlib/with-resources.tl"
"./share/txr/stdlib/yield.tl" "./share/txr/stdlib/conv.tl" "./share/txr/stdlib/termios.tl")</syntaxhighlight>
For a regex pattern we can replace <code>(endswith ".tl" path)</code> with something like <code>(m$ path #/\.tl/)</code>.
TXR also provides the <code>fnmatch</code> function which can be used to match using a file globbing pattern.
<pre>1< (fnmatch "*.tl" "foo.tl")
t
2>< (fnmatch "*.tl" "foo.c")
nil</pre>
The <code>type</code>, <code>stat</code>, <code>level</code> and <code>base</code> callback arguments we are ignoring closely follow those of the POSIX C <code>nftw</code> function. <code>type</code> is a type code which indicates the kind of item visited: file, directory; <code>stat</code> is a Lisp version of <code>struct stat</code>, providing various information about the filesystem object: permissions, timestamps, inode number, etc.
A nice approach would be to capture a continuation in the callback, and then obtain the walk elements lazily; alas, capturing a continuation from a C library function's callback is not permitted, because the capture would span foreign stack frames.
===Using <code>glob*</code>===
TXR has a <code>glob*</code> function which, like <code>glob</code> is built on the POSIX C library function. <code>glob*</code> also provides Bash-style brace expansion, as well as the double star pattern, which we can use to find files recursively:
<syntaxhighlight lang="txrlisp">(glob* "**/*.c")</syntaxhighlight>
{{out}}
<syntaxhighlight lang="txrlisp">("args.c" "arith.c" "autoload.c" "buf.c" "cadr.c" "chksum.c" "chksums/crc32.c"
"chksums/md5.c" "chksums/sha1.c" "chksums/sha256.c" "combi.c"
"debug.c" "eval.c" "ffi.c" "filter.c" "ftw.c" "gc.c" "glob.c"
"gzio.c" "hash.c" "itypes.c" "lib.c" "linenoise/example.c" "linenoise/linenoise.c"
"match.c" "mpi/mpi.c" "mpi/mplogic.c" "parser.c" "protsym.c"
"psquare.c" "rand.c" "regex.c" "signal.c" "socket.c" "stream.c"
"struct.c" "strudel.c" "sysif.c" "syslog.c" "termios.c" "time.c"
"tree.c" "txr.c" "unwind.c" "utf8.c" "vm.c")</syntaxhighlight>
=={{header|UNIX Shell}}==
{{works with|Bourne Again SHell}}
The "find" command gives a one-line solution for simple patterns:
<
"find" can also be used to find files matching more complex patterns as illustrated in the section on [[#UnixPipes|Unix Pipes]] below.
Using "bash" version 4 or later, you can use "globstar" or "dotglob", depending on whether you want hidden directories to be searched:
<
# Warning: globstar excludes hidden directories.
# Turn on recursive globbing (in this script) or exit if the option is not supported:
Line 1,822 ⟶ 2,702:
echo "$f"
fi
done</
Here is a solution that does not use "find".
<
indent_print()
Line 1,866 ⟶ 2,746:
}
walk_tree "$1" "\.sh$"</
A simplified version that gives the same output:
<
walk_tree() {
Line 1,881 ⟶ 2,761:
}
walk_tree "$1" "\.sh$"</
=={{header|UnixPipes}}==
As illustrated [[#UNIX Shell|above]], the "find" command can be used with the -name option to match simple patterns. To find files matching more complex patterns, the results of "find" can be piped, e.g.
<
One way to run a command against each file that is found is to use "xargs", but if there is any possibility that a filename contains a space or tab character, then the following model should be used:
<
=={{header|Visual Basic .NET}}==
{{works with|Visual Basic .NET|9.0+}}
This uses the OS pattern matching
<syntaxhighlight lang="vbnet">Sub walkTree(ByVal directory As IO.DirectoryInfo, ByVal pattern As String)
For Each file In directory.GetFiles(pattern)
Console.WriteLine(file.FullName)
Next
For Each subDir In directory.GetDirectories
walkTree(subDir, pattern)
Next
End Sub</syntaxhighlight>
=={{header|Wren}}==
{{libheader|Wren-pattern}}
{{libheader|Wren-sort}}
<syntaxhighlight lang="wren">import "io" for Directory, File
import "./pattern" for Pattern
import "./sort" for Sort
var walk // recursive function
walk = Fn.new { |dir, pattern, found|
if (!Directory.exists(dir)) Fiber.abort("Directory %(dir) does not exist.")
var files = Directory.list(dir)
for (f in files) {
var path = dir + "/%(f)"
if (File.exists(path)) { // it's a file not a directory
if (pattern.isMatch(f)) found.add(f)
} else {
walk.call(path, pattern, found)
}
}
}
// get all C header files beginning with 'va' or 'vf'
var p = Pattern.new("v[a|f]+0^..h", Pattern.whole)
var found = []
walk.call("/usr/include", p, found)
Sort.quick(found)
for (f in found) System.print(f)</syntaxhighlight>
{{out}}
<pre>
valarray_after.h
valarray_array.h
valarray_before.h
valgrind.h
validate.h
values.h
vfio.h
vfio_ccw.h
vfs.h
</pre>
=={{header|zkl}}==
<
Lots of options, here I'm using the defaults: recurse, just file matches (not directory names) and return a bit bucket of ASCIIZ strings.
{{out}}
Line 1,906 ⟶ 2,839:
</pre>
globular will write to a object that has a write method or just call a method or function, which is nice for sending data to other threads (eg multi-threaded find/grep). To do the above example in one shot (without saving the results):
<
=={{header|Zsh}}==
Zsh has recursive globbing. The GLOB_DOTS option allows files beginning with a period to be matched.
<
print -l -- **/*.txt</
GLOB_DOTS can be set temporarily with the 'D' modifier.
<
{{omit from|ACL2|Very limited filesystem support.}}
Line 1,921 ⟶ 2,854:
{{omit from|PARI/GP}}
{{omit from|Retro}}
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have a filesystem, just namespaced variables, which can't be listed from a program. -->
{{omit from|Unlambda|Does not have file system support.}}
{{omit from|ZX Spectrum Basic|Does not have subdirectories}}
|