Walk a directory/Non-recursively: Difference between revisions

From Rosetta Code
Content added Content deleted
(Add zsh)
(omit from Unlambda)
Line 563: Line 563:
{{omit from|M4}}
{{omit from|M4}}
{{omit from|Befunge}} <!-- No filesystem support -->
{{omit from|Befunge}} <!-- No filesystem support -->
{{omit from|Unlambda|Does not have file system support.}}

Revision as of 11:15, 7 August 2010

Task
Walk a directory/Non-recursively
You are encouraged to solve this task according to the task description, using any language you may know.

Walk a given directory and print the names of files matching a given pattern.

Note: This task is for non-recursive methods. These tasks should read a single directory, not an entire directory tree. For code examples that read entire directory trees, see Walk Directory Tree

Note: Please be careful when running any code presented here.

Ada

Works with: GCC version 4.12

<lang ada>with Ada.Directories; use Ada.Directories; with Ada.Text_IO; use Ada.Text_IO;

procedure Walk_Directory

           (Directory : in String := ".";
            Pattern   : in String := "") -- empty pattern = all file names/subdirectory names

is

  Search  : Search_Type;
  Dir_Ent : Directory_Entry_Type;

begin

  Start_Search (Search, Directory, Pattern);
  while More_Entries (Search) loop
     Get_Next_Entry (Search, Dir_Ent);
     Put_Line (Simple_Name (Dir_Ent));
  end loop;
  End_Search (Search);

end Walk_Directory;</lang>

ALGOL 68

Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386 - uses non-standard library routines get directory and grep in string.

<lang algol68>INT match=0, no match=1, out of memory error=2, other error=3;

[]STRING directory = get directory("."); FOR file index TO UPB directory DO

 STRING file = directory[file index];
 IF grep in string("[Ss]ort*.[.]a68$", file, NIL, NIL) = match THEN
   print((file, new line))
 FI

OD</lang> Sample Output:

Quick_sort.a68
Shell_sort.a68
Cocktail_Sort.a68
Selection_Sort.a68
Merge_sort.a68
Bobosort.a68
Insertion_Sort.a68
Permutation_Sort.a68

AppleScript

AppleScript itself has limited built-in file system access. Typically, the Mac OS Finder is used to gather such information. To list all file/folders in the root directory:<lang AppleScript>tell application "Finder" to return name of every item in (startup disk) --> EXAMPLE RESULT: {"Applications", "Developer", "Library", "System", "Users"}</lang> To list all pdf files in user's home directory: <lang AppleScript>tell application "Finder" to return name of every item in (path to documents folder from user domain) whose name ends with "pdf" --> EXAMPLE RESULT: {"About Stacks.pdf", "Test.pdf"}</lang> The key clause is the whose modifier keyword. The Finder can interpret many variations, including such terms as whose name begins with, whose name contains, etc. As well as boolean combinations:<lang AppleScript>tell application "Finder" to return name of every item in (path to documents folder from user domain) whose name does not contain "about" and name ends with "pdf" --> RETURNS: {"Test.pdf"}</lang> The Finder also supports the entire contents modifier keyword, which effectively performs a recursive directory scan without recursion.<lang AppleScript>tell application "Finder" to return name of every item in entire contents of (path to documents folder from user domain) whose name ends with "pdf"</lang>

AutoHotkey

Display all INI files in Windows directory. <lang autohotkey>Loop, %A_WinDir%\*.ini

out .= A_LoopFileName "`n"

MsgBox,% out</lang>

BASIC

Works with: QuickBasic version 7.1

(older versions don't have DIR$)

DOS wildcards are rather retarded when compared to... well... anything else.

<lang qbasic>DECLARE SUB show (pattern AS STRING)

show "*.*"

SUB show (pattern AS STRING)

   DIM f AS STRING
   f = DIR$(pattern)
   DO WHILE LEN(f)
       PRINT f
       f = DIR$
   LOOP

END SUB </lang>

C

Works with: POSIX version .1-2001

In this example, the pattern is a POSIX extended regular expression. <lang c>#include <sys/types.h>

  1. include <dirent.h>
  2. include <regex.h>
  3. include <stdio.h>

void walker(const char *dir, const char *pattern) {

   struct dirent *entry;
   regex_t reg;
   DIR *d; 
   if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB))
       return;
   if (!(d = opendir(dir)))
       return;
   while (entry = readdir(d))
       if (!regexec(&reg, entry->d_name, 0, NULL, 0))
           puts(entry->d_name);
   closedir(d);

}

int main() {

   walker(".", ".\\.c$");
   return 0;

}</lang>

C++

Library: boost version 1.38.0

<lang cpp>#include "boost/filesystem.hpp"

  1. include "boost/regex.hpp"
  2. include <iostream>

using namespace boost::filesystem;

int main() {

 path current_dir(".");
 boost::regex pattern("a.*"); // list all files starting with a
 for (directory_iterator iter(current_dir), end;
      iter != end;
      ++iter)
 {
   std::string name = iter->path().leaf();
   if (regex_match(name, pattern))
     std::cout << name << "\n";
 }

}</lang>

C#

<lang csharp>using System; using System.IO;

namespace DirectoryWalk {

   class Program
   {
       static void Main(string[] args)
       {
           string[] filePaths = Directory.GetFiles(@"c:\MyDir", "a*");
           foreach (string filename in filePaths)
               Console.WriteLine(filename);            
       }
   }

} </lang>

ColdFusion

This example display all files and directories directly under C:\temp that end with .html <lang cfm><cfdirectory action="list" directory="C:\temp" filter="*.html" name="dirListing"> <cfoutput query="dirListing">

 #dirListing.name# (#dirListing.type#)

</cfoutput></lang>

Common Lisp

<lang lisp>(defun walk-directory (directory pattern)

 (directory (merge-pathnames pattern directory)))</lang>

Uses the filename pattern syntax provided by the CL implementation.

D

See also the D code at Walk Directory Tree. <lang d>import std.stdio; import std.file; import std.path ;

void main(string[] args) {

 auto path = args.length > 1 ? args[1] : "." ; // default current 
 auto pattern = args.length > 2 ? args[2] : "*.*"; // default all file 
   
 bool matchNPrint(DirEntry* de){
   if(!de.isdir && fnmatch(de.name, pattern))
     writefln(de.name) ; 
   return true ; // continue
 }       
 listdir(path, &matchNPrint) ;
}</lang>

E

<lang e>def walkDirectory(directory, pattern) {

 for name => file ? (name =~ rx`.*$pattern.*`) in directory {
   println(name)
 }

}</lang>

Example:

<lang e>? walkDirectory(<file:~>, "bash_") .bash_history .bash_profile .bash_profile~</lang>

F#

<lang fsharp> System.IO.Directory.GetFiles("c:\\temp", "*.xml") |> Array.iter (printfn "%s") </lang>

Forth

Works with: gforth version 0.6.2

Gforth's directory walking functions are tied to the POSIX dirent functions, used by the C langauge entry above. Forth doesn't have regex support, so a simple filter function is used instead.

<lang forth>defer ls-filter ( name len -- ? )

ls-all 2drop true ;
ls-visible drop c@ [char] . <> ;
ls ( dir len -- )
 open-dir throw  ( dirid )
 begin
   dup pad 256 rot read-dir throw
 while
   pad over ls-filter if
     cr pad swap type
   else drop then
 repeat
 drop close-dir throw ;

\ only show C language source and header files (*.c *.h)

c-file? ( str len -- ? )
 dup 3 < if 2drop false exit then
 + 1- dup c@
  dup [char] c <> swap [char] h <> and if drop false exit then
 1- dup c@ [char] . <> if drop false exit then
 drop true ;

' c-file? is ls-filter

s" ." ls</lang>

Groovy

<lang groovy>// *** print *.txt files in current directory

new File('.').eachFileMatch(~/.*\.txt/) {
  println it
}
// *** print *.txt files in /foo/bar
new File('/foo/bar').eachFileMatch(~/.*\.txt/) {
  println it
}</lang>

Haskell

Works with: GHCi version 6.6

In this example, the pattern is a POSIX extended regular expression. <lang haskell>import System.Directory import Text.Regex import Data.Maybe

walk :: FilePath -> String -> IO () walk dir pattern = do

   filenames <- getDirectoryContents dir
   mapM_ putStrLn $ filter (isJust.(matchRegex $ mkRegex pattern)) filenames

main = walk "." ".\\.hs$"</lang>

HicEst

More on SYSTEM, OPEN, INDEX <lang hicest>CHARACTER dirtxt='dir.txt', filename*80

SYSTEM(DIR='*.*', FIle=dirtxt) ! "file names", length, attrib, Created, LastWrite, LastAccess OPEN(FIle=dirtxt, Format='"",', LENgth=files) ! parses column 1 ("file names")

DO nr = 1, files

 filename = dirtxt(nr,1) ! reads dirtxt row = nr, column = 1 to filename
 ! write file names with extensions "txt", or "hic", or "jpg" (case insensitive) using RegEx option =128:
 IF( INDEX(filename, "\.txt|\.hic|\.jpg", 128) ) WRITE() filename 

ENDDO</lang>

IDL

<lang idl>f = file_search('*.txt', count=cc) if cc gt 0 then print,f</lang>

(IDL is an array language - very few things are ever done in 'loops'.)

J

<lang j>require 'dir' 0 dir '*.png' 0 dir '/mydir/*.txt'</lang> The verb dir supports a number of formatting options determined by its left argument. A left argument of 0 reports just the file names.

Java

<lang java>File dir = new File("/foo/bar");

String[] contents = dir.list(); for (String file : contents)

   if (file.endsWith(".mp3"))
       System.out.println(file);</lang>

JavaScript

Works with: JScript

<lang javascript>var fso = new ActiveXObject("Scripting.FileSystemObject"); var dir = fso.GetFolder('test_folder');

function walkDirectory(dir, re_pattern) {

   WScript.Echo("Files in " + dir.name + " matching '" + re_pattern +"':");
   walkDirectoryFilter(dir.Files, re_pattern);
   WScript.Echo("Folders in " + dir.name + " matching '" + re_pattern +"':");
   walkDirectoryFilter(dir.Subfolders, re_pattern);

}

function walkDirectoryFilter(items, re_pattern) {

   var e = new Enumerator(items);
   while (! e.atEnd()) {
       var item = e.item();
       if (item.name.match(re_pattern))
           WScript.Echo(item.name);
       e.moveNext();
   }

}

walkDirectory(dir, '\\.txt$');</lang>

Mathematica

The built-in function FileNames does exactly this: <lang Mathematica>FileNames[] lists all files in the current working directory. FileNames[form] lists all files in the current working directory whose names match the string pattern form. FileNames[{form1,form2,...}] lists all files whose names match any of the form_i. FileNames[forms,{dir1,dir2,...}] lists files with names matching forms in any of the directories dir_i. FileNames[forms,dirs,n] includes files that are in subdirectories up to n levels down.</lang> Examples (find all files in current directory, find all png files in root directory): <lang Mathematica>FileNames["*"] FileNames["*.png", $RootDirectory]</lang> the result can be printed with Print /@ FileNames[....].

MAXScript

<lang maxscript>getFiles "C:\\*.txt"</lang>

Objective-C

<lang objc>NSString *dir = @"/foo/bar";

NSArray *contents = [[NSFileManager defaultManager] directoryContentsAtPath:dir]; NSEnumerator *enm = [contents objectEnumerator]; NSString *file; while ((file = [enm nextObject]))

 if ([[file pathExtension] isEqualToString:@"mp3"])
   NSLog(@"%@", file);</lang>

OCaml

<lang ocaml>#load "str.cma" let contents = Array.to_list (Sys.readdir ".") in let select pat str = Str.string_match (Str.regexp pat) str 0 in List.filter (select ".*\\.jpg") contents</lang>

Oz

<lang oz>declare

 [Path] = {Module.link ['x-oz://system/os/Path.ozf']}
 [Regex] = {Module.link ['x-oz://contrib/regex']}
 Files = {Filter {Path.readdir "."} Path.isFile}
 Pattern = ".*\\.oz$"
 MatchingFiles = {Filter Files fun {$ File} {Regex.search Pattern File} \= false end}

in

 {ForAll MatchingFiles System.showInfo}</lang>

Perl

<lang perl>opendir my $dh, 'the_directory'; print "$_\n" foreach grep /foo/, readdir $dh; closedir $dh;</lang>

Or using globbing: <lang perl>print "$_\n" while </home/foo/bar/*.php>;</lang>

PHP

Works with: PHP version 5.2.0

<lang php>$pattern = 'php'; $dh = opendir('c:/foo/bar'); // Or '/home/foo/bar' for Linux while (false !== ($file = readdir($dh))) {

   if ($file != '.' and $file != '..')
   {
       if (preg_match("/$pattern/", $file))
       {
           echo "$file matches $pattern\n";
       }
   }

} closedir($dh);</lang> Or: <lang php>$pattern = 'php'; foreach (scandir('/home/foo/bar') as $file) {

   if ($file != '.' and $file != '..')
   {
       if (preg_match("/$pattern/", $file))
       {
           echo "$file matches $pattern\n";
       }
   }

}</lang>

Works with: PHP version 4 >= 4.3.0 or 5

<lang php>foreach (glob('/home/foo/bar/*.php') as $file){

   echo "$file\n";

}</lang>

PicoLisp

<lang PicoLisp>(for F (dir "@src/") # Iterate directory

  (when (match '`(chop "s@.c") (chop F))    # Matches 's*.c'?
     (println F) ) )                        # Yes: Print it</lang>

Output:

"start.c"
"ssl.c"
"subr.c"
"sym.c"
...

Pop11

Built-in procedure sys_file_match searches directories (or directory trees) using shell-like patterns: <lang pop11>lvars repp, fil;

create path repeater

sys_file_match('*.p', , false, 0) -> repp;

iterate over files

while (repp() ->> fil) /= termin do

    ;;; print the file
    printf(fil, '%s\n');

endwhile;</lang>


PowerShell

Since PowerShell is also a shell it should come as no surprise that this task is very simple. Listing the names of all text files, or the names of all files, starting with "f": <lang powershell>Get-ChildItem *.txt -Name Get-ChildItem f* -Name</lang> The -Name parameter tells the Get-ChildItem to return only the file names as string, otherwise a complete FileInfo or DirectoryInfo object would be returned, containing much more information than only the file name.

More complex matching can be accomplished by filtering the complete list of files using the Where-Object cmdlet. The following will output all file names that contain at least one vowel: <lang powershell>Get-ChildItem -Name | Where-Object { $_ -match '[aeiou]' }</lang>

PureBasic

The match is made using DOS wildcards. It could easily be modified to match based on a regular expression if desired (i.e. using the PCRE library). <lang PureBasic>Procedure walkDirectory(directory.s = "", pattern.s = "")

 Protected directoryID
 
 directoryID = ExamineDirectory(#PB_Any,directory,pattern)
 If directoryID
   While NextDirectoryEntry(directoryID)
     PrintN(DirectoryEntryName(directoryID))
   Wend
   FinishDirectory(directoryID)
 EndIf 

EndProcedure

If OpenConsole()

 walkDirectory()  
 
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit")
 Input()
 CloseConsole()

EndIf</lang>

Python

The glob library included with Python lists files matching shell-like patterns:

<lang python>import glob for filename in glob.glob('/foo/bar/*.mp3'):

   print filename</lang>

Or manually:

<lang python>import os for filename in os.listdir('/foo/bar'):

   if filename.endswith('.mp3')
       print filename</lang>

R

<lang R>dir("/foo/bar", "mp3")</lang>

Raven

<lang raven>'dir://.' open each as item

   item m/\.txt$/ if "%(item)s\n" print</lang>

Ruby

<lang ruby># Files under this directory: Dir.glob('*') { |file| puts file }

  1. Files under path '/foo/bar':

Dir.glob( File.join('/foo/bar', '*') ) { |file| puts file }

  1. As a method

def file_match(pattern=/\.txt/, path='.')

 Dir[File.join(path,'*')].each do |file|
   puts file if file =~ pattern
 end

end</lang>

Smalltalk

<lang smalltalk>(Directory name: 'a_directory')

 allFilesMatching: '*.st' do: [ :f | (f name) displayNl ]</lang>

Tcl

For the current directory: <lang tcl>foreach filename [glob *.txt] {

   puts $filename

}</lang> For an arbitrary directory: <lang tcl>set dir /foo/bar foreach filename [glob -directory $dir *.txt] {

   puts $filename
   ### Or, if you only want the local filename part...
   # puts [file tail $filename]

}</lang>

Toka

As with the C example, this uses a a POSIX extended regular expression as the pattern. The dir.listByPattern function used here was introduced in library revision 1.3.

<lang toka>needs shell " ." " .\\.txt$" dir.listByPattern</lang>

Visual Basic .NET

Works with: Visual Basic .NET version 9.0+

<lang vbnet>'Using the OS pattern matching For Each file In IO.Directory.GetFiles("\temp", "*.txt")

 Console.WriteLine(file)

Next

'Using VB's pattern matching and LINQ For Each file In (From name In IO.Directory.GetFiles("\temp") Where name Like "*.txt")

 Console.WriteLine(file)

Next

'Using VB's pattern matching and dot-notation For Each file In IO.Directory.GetFiles("\temp").Where(Function(f) f Like "*.txt")

 Console.WriteLine(file)

Next</lang>

UnixPipes

ls can take a file globbing pattern too. here using grep for regexp. <lang bash>ls | grep '\.c$'</lang>

Zsh

Zsh has powerful filename generation features, which can filter by file names, permissions, size, type, etc. <lang bash>print -l -- *.c</lang>