19
\$\begingroup\$

Goal:

Create a program to find the smallest file in the current folder.

  • File size may be measured in bytes or characters.
  • If multiple files have the same size, you can either choose one or display all of them.
  • You can assume there will be at least one file in the folder, and no files will have a size of 0.
  • Assume that all files in the folder can be loaded by the language you're using.

  • Assume that there are no folders in the current directory.

Input:

The program should not take any input from the user, unless:

  • If your language doesn't have a "current folder", it may ask the user for a folder name/path.
  • If your language cannot directly access files on your computer, it may allow the user to upload files. (JavaScript, for example)

Output:

The name of the smallest file should be displayed.

  • Leading/trailing symbols are allowed, as long as it's clear which file has been chosen.
  • (Printing a list of all the files is against the rules).

Notes:

  • Standard Loopholes are not allowed.
  • You cannot modify/create/delete files in the folder to change the result.
  • This is ; shortest answer (in bytes) wins.
\$\endgroup\$
  • 1
    \$\begingroup\$ Can we assume files can have a size of 0? \$\endgroup\$ – Rɪᴋᴇʀ Jan 27 '17 at 21:27
  • \$\begingroup\$ Also, what does "assume that all files in the folder can be accessed" mean? does that mean hidden files don't need to be shown? \$\endgroup\$ – Rɪᴋᴇʀ Jan 27 '17 at 21:28
  • 2
    \$\begingroup\$ Can I assume there are no folders on the current folder? It makes all the difference if you have a language function that returns both files and folders instead of only files! \$\endgroup\$ – sergiol Jan 28 '17 at 1:39
  • 1
    \$\begingroup\$ Not necessarily. You may assume that there are no directories inside the current directory is unambiguous and doesn't invalidate any answers. \$\endgroup\$ – Dennis Jan 28 '17 at 3:31
  • 1
    \$\begingroup\$ (sorry I haven't replied sooner, my internet connection was down for a few days) The problem I have with allowing you to skip hidden files is that it seems to open a lot of loopholes. Allowing you to skip files that are "slightly harder to access" would mean people could do something like only checking the first 9 files because it saves a few bytes. \$\endgroup\$ – 12Me21 Jan 30 '17 at 13:59

26 Answers 26

7
\$\begingroup\$

Vim 12 bytes

!!ls -Sa
Gd{

Try it online!

Explanation:

!! is the filter command. It pipes the contents of the current line to an arbitrary system command, and sends the output back into the buffer. It's useful for using external tools for things that bash is better at than vim, for example !!rev to reverse the current line, or !Gxxd to hexdump the buffer. In our case, the buffer is empty so it's equivalent to :r!ls, which just feeds the output of the command into the current line.

Now the cursor is on line 1, and we want to delete every line but the last one. The naïve approach is

G       " Go to the last line
 k      " Go up one line
  d     " Delete:
   gg   "   Everything up to the first line

But we can do better. Like I explained in this tip, the { can usually (but not always) be equivalent to gg. Here, it's even better. Because the motion is character-based, not line-based like gg is, we don't have to go up a line first, leaving us with

Gd{
\$\endgroup\$
16
\$\begingroup\$

Bash + coreutils, 13 bytes

ls -Sar|sed q

Explanation:

ls -Sar|sed q
ls            # list files
   -S         # sorted, biggest first
     a        # show hidden files
      r       # reversed (smallest first)
       |sed q # q is quit at first line that matches given regex, 
              # given regex is empty so guaranteed match.         
\$\endgroup\$
  • \$\begingroup\$ Posted this as my own answer, but I think it's too similar to yours. ls -1Sa|tail -1 is 3 bytes shorter and has cleaner output. \$\endgroup\$ – orlp Jan 27 '17 at 21:32
  • \$\begingroup\$ @orlp thanks!.. \$\endgroup\$ – Rɪᴋᴇʀ Jan 27 '17 at 21:33
  • 1
    \$\begingroup\$ I don't think you need the '-1', pipe automatically puts one file per line. \$\endgroup\$ – G B Jan 27 '17 at 21:35
  • \$\begingroup\$ @EasterlyIrk I think GB is right. if ls detects output is to the terminal it will format the output into multiple columns. But if output is a pipe it will just do 1 per line. Compare ls vs ls|cat \$\endgroup\$ – Digital Trauma Jan 27 '17 at 21:41
  • \$\begingroup\$ Two bytes shorter: ls -Sar|sed q \$\endgroup\$ – Digital Trauma Jan 27 '17 at 21:41
8
\$\begingroup\$

Python 2 3, 94 76 74 54 bytes

-18 bytes thanks to @orlp
-2 bytes thanks to @Jonathan Allan
-20 bytes thanks to a change in challenge specs

from os import*
print(min(listdir(),key=path.getsize))
\$\endgroup\$
  • \$\begingroup\$ print min(filter(path.isfile,listdir(".")),key=path.getsize) is cleaner and substantially shorter. \$\endgroup\$ – orlp Jan 27 '17 at 21:36
  • \$\begingroup\$ Save two bytes moving to Python 3 since "." is the default. print(min(filter(path.isfile,listdir()),key=path.getsize)) \$\endgroup\$ – Jonathan Allan Jan 27 '17 at 22:14
  • \$\begingroup\$ Also I count 76 not 77. \$\endgroup\$ – Jonathan Allan Jan 27 '17 at 22:19
  • \$\begingroup\$ @JonathanAllan I measured the byte count count with wc which gave me 1 byte more \$\endgroup\$ – ovs Jan 27 '17 at 22:30
  • \$\begingroup\$ The extraneous byte would be due to a trailing newline, which is not required for Python. Additionally, since the challenge was updated to state that there are no subdirectories present, the whole filter bit is unnecesary. This also doesn't work in Python 3, since print is a function. The following would work, and be substantially shorter: print(min(listdir(),key=path.getsize)) \$\endgroup\$ – Mego Jan 28 '17 at 4:34
8
\$\begingroup\$

PowerShell, 30 24 21 bytes

(ls|sort le*)[0].Name

Try it online!

ls is an alias for Get-ChildItem. That's piped to sort-object with the length attribute, so the files are sorted by size. We index into that with the (...)[0] to get the first (i.e., smallest), and then take the .Name thereof. Output via implicit Write-Output happens at program completion.

Saved 6 bytes since we're guaranteed that only files exist in the directory. Saved an additional 3 thanks to ConnorLSW.

\$\endgroup\$
  • 2
    \$\begingroup\$ Can you not get rid of the -file since only files are in the current directory? \$\endgroup\$ – Mutantoe Jan 28 '17 at 11:13
  • \$\begingroup\$ @Mutantoe Yes -- that was edited into the challenge after I posted this answer. Thanks! \$\endgroup\$ – AdmBorkBork Jan 29 '17 at 19:19
  • \$\begingroup\$ you can use sort le* to shave some bytes since powershell will accept it. \$\endgroup\$ – colsw Jan 30 '17 at 14:48
  • \$\begingroup\$ @ConnorLSW Yes, of course. Thanks! \$\endgroup\$ – AdmBorkBork Jan 30 '17 at 14:56
7
\$\begingroup\$

Ruby, 61 40 38 37 bytes

Thanks G B and Value Ink

p Dir[?*,".*"].min_by{|x|File.size x}
\$\endgroup\$
  • \$\begingroup\$ You can use ?. instead of Dir.pwd, and min_by{} to get the smallest file. Dir.foreach(?.).min_by{|x|File.size x} gets the same result in 38 bytes. \$\endgroup\$ – G B Jan 27 '17 at 21:41
  • \$\begingroup\$ @GB Thanks! \$\endgroup\$ – dkudriavtsev Jan 27 '17 at 23:03
  • \$\begingroup\$ It's a shame that "all" files the language can access must be looked at, because Dir[?*] is much shorter but doesn't include hidden Unix files like .bash_profile... \$\endgroup\$ – Value Ink Jan 28 '17 at 2:02
  • \$\begingroup\$ Maybe Dir[?*,".?*"] could work. I haven't tried. And it's shorter. \$\endgroup\$ – G B Jan 28 '17 at 15:09
  • \$\begingroup\$ @GB It'd actually be Dir[?*,".*"]. Glob string .?* won't match file .a if it exists. \$\endgroup\$ – Value Ink Feb 1 '17 at 23:11
6
\$\begingroup\$

Mathematica, 35 bytes

FileNames[]~MinimalBy~FileByteCount

FileNames[] produces a list of names of all the files (and directories) in the current directory; ~MinimalBy~FileByteCount selects the name of the file whose byte count is smallest. FileByteCount throws a bunch of errors when it's applied to directories, but the errors don't derail the program.

\$\endgroup\$
6
\$\begingroup\$

Java 7, 149 142 bytes

String f(){String n="";long s=-1>>>1,p;for(java.io.File f:new java.io.File(".").listFiles())if((p=f.length())<s){n=f.getName();s=p;}return n;}

Try it online!

-7 bytes thanks to CAD97

\$\endgroup\$
  • \$\begingroup\$ I think you want File::length not File::getTotalSpace \$\endgroup\$ – CAD97 Jan 29 '17 at 7:24
  • \$\begingroup\$ Untested Java 8: ()->java.utils.stream(new java.io.File(".").listFiles()).max((a,b)->a.length()-b.length).get().getName() for 104 bytes \$\endgroup\$ – CAD97 Jan 29 '17 at 7:31
  • \$\begingroup\$ @CAD97 You're right! What was I thinking... \$\endgroup\$ – Poke Jan 29 '17 at 16:09
6
\$\begingroup\$

SH (Linux/Unix) 15 14 13 14 bytes

ls -aS|tail -1

-S sorts by size (descending),

-rreverses and tail -1 outputs the last file in the list.

@ Dennis Thanks for saving 1 byte @Dani_l Thanks for saving 1 byte.

\$\endgroup\$
  • \$\begingroup\$ That finds the largest file, no? \$\endgroup\$ – Dennis Jan 28 '17 at 5:52
  • \$\begingroup\$ Nevermind, I'm tired. You could use tail though instead of reversing, and -1 is a shorthand for -n1. \$\endgroup\$ – Dennis Jan 28 '17 at 5:55
  • \$\begingroup\$ @Dennis Updated \$\endgroup\$ – Abel Tom Jan 28 '17 at 5:58
  • \$\begingroup\$ @EasterlyIrk Now it should :) \$\endgroup\$ – Abel Tom Jan 29 '17 at 14:47
  • \$\begingroup\$ @AbelTom cool, thanks for fixing. \$\endgroup\$ – Rɪᴋᴇʀ Jan 29 '17 at 14:47
4
\$\begingroup\$

MATLAB / Octave, 52 48 bytes

d=dir;[~,n]=min([d.bytes]./~[d.isdir]);d(n).name

Explanation

This gets a directory listing of all files and folders in the current directory using dir. The output of dir is a struct containing the filename, whether it's a directory or not, the size (in bytes), etc.

We can then take an array of the sizes of each in bytes [d.bytes] and perform element-wise division with a boolean indicating whether it's a directory or not ~[d.isdir] which will yield Inf where it's a directory (division by zero) and the size in bytes otherwise (division by 1).

We find the index of the minimum of this array using the second output of min and use that to index into the initial struct and display the name with d(n).name

\$\endgroup\$
  • \$\begingroup\$ You should add disp(...) around the output to properly print it. Otherwise if for example there was a file called ans that is not the smallest in the folder the output wouldn't be clear as to which file is the smallest to anyone unfamiliar with MATLAB. \$\endgroup\$ – Tom Carpenter Jan 28 '17 at 15:33
  • \$\begingroup\$ @TomCarpenter Hmmm I interpreted "Leading/trailing symbols are allowed, as long as it's clear which file has been chosen" to mean that the ans = is ok \$\endgroup\$ – Suever Jan 28 '17 at 15:37
  • \$\begingroup\$ I've just realised MATLAB adds the implicit . (current folder) and .. (folder above), so cant remove the directory check it seems. Sorry about that. \$\endgroup\$ – Tom Carpenter Jan 28 '17 at 15:38
4
\$\begingroup\$

Scala, 52 bytes

Old version, 79 bytes

new java.io.File(".").listFiles.map(a=>a.getName->a.length)sortBy(_._2)apply(0)

Adjusted according to jaxad0127's advice. It is only 52 bytes now.

new java.io.File(".").listFiles.sortBy(_.length)head
\$\endgroup\$
  • \$\begingroup\$ Using head instead of apply(0) is shorter. Also, the toString method of File is fine, no need to call get name. \$\endgroup\$ – jaxad0127 Jan 29 '17 at 6:42
4
\$\begingroup\$

Batch, 43 39 35 bytes

@dir/b/os|(set/pf=&call echo %%f%%)

Output includes a leading space for some reason, but fortunately that's allowed. Edit: Now assuming there are no directories to save 4 bytes.

\$\endgroup\$
  • \$\begingroup\$ Oh, using /p like that, dang clever! \$\endgroup\$ – AdmBorkBork Jan 27 '17 at 22:11
  • \$\begingroup\$ @AdmBorkBork Ah, I hadn't noticed that was allowed, thanks! \$\endgroup\$ – Neil Jan 27 '17 at 23:52
  • \$\begingroup\$ You're guaranteed that no sub-directories exist (the challenge was updated) so you can eliminate the /a-d. \$\endgroup\$ – AdmBorkBork Jan 29 '17 at 19:30
4
\$\begingroup\$

Perl 6,  33 32 31  16 bytes

'.'.IO.dir.grep(*.f).min(*.s).put

Try it

put '.'.IO.dir.min:{try .s//Inf}

Try it

put $*CWD.dir.min:{try .s//Inf}

Try it

put dir.min: *.s

Try it

Expanded:

put        # print with trailing newline
dir        # the list of files in the current directory
.min:      # find the minimum by
  *.s      # calling the `s` method (size) in a Whatever lambda
\$\endgroup\$
  • \$\begingroup\$ The function form of dir defaults to $*CWD, and the task description says you can assume there won't be any folders, so I think you can shorten that to dir.min(*.s).put. \$\endgroup\$ – smls Jan 29 '17 at 20:42
  • \$\begingroup\$ When I wrote this, it said the program must ignore folders. \$\endgroup\$ – Brad Gilbert b2gills Jan 29 '17 at 21:36
4
\$\begingroup\$

J, 21 20 bytes

>{.,(/:2&{"1)1!:0'*'

Saved a byte thanks to @Conor.

Explanation

>{.,(/:2&{"1)1!:0'*'
                 '*' Glob all files in current directory
             1!:0    Table of file metadata in that directory
       2&{"1         Get the file size of each
     /:              Sort the files by that
   ,                 Flatten
 {.                  Get the first value
>                    Unbox
\$\endgroup\$
  • \$\begingroup\$ @ConorO'Brien Thanks \$\endgroup\$ – miles Mar 8 '17 at 2:52
3
\$\begingroup\$

BATCH File, 77 72 63 bytes

@FOR /F "tokens=*" %%G IN ('dir/o-s/b') DO @SET F=%%G
@ECHO %F%

There's no direct equivalent of head or tail in BATCH, at least to my knowledge, so here's a kludgy work-around. (with much assistance from @Neil - thanks!)

The dir command, with /o-s to sort in descending file size, and /b to output only the file names. We loop through those with FOR /F, setting the variable F to the file name each time. Finally, we output just the last one with ECHO %F%.

Saved 9 more bytes thanks to Neil and thanks to guarantees that no directories are present.

\$\endgroup\$
  • 1
    \$\begingroup\$ Your FOR variable needs two %s to work in a script. Otherwise, a few golfing tricks: 1. Don't use @ECHO OFF on short scripts, add a @ to each line and after DO. 2. Delete the space before DO. 3. The spaces and :s aren't needed in the dir command. \$\endgroup\$ – Neil Jan 27 '17 at 21:54
  • 1
    \$\begingroup\$ @Neil Ack, thanks. Sorry, pretty rusty since I've been doing PowerShell... Thanks! \$\endgroup\$ – AdmBorkBork Jan 27 '17 at 22:01
3
\$\begingroup\$

PHP, 84 62 bytes

$t=array_map(filesize,$g=glob('*'));asort($t);echo$g[key($t)];

Since the question was updated with the assumption that there will be no folders in the current directory, I was able to remove the file check stuff and golf this down.


Here is my old answer:

$t=array_map(filesize,$g=array_filter(glob('*'),is_file));asort($t);echo$g[key($t)];

This is the best I could do. Maybe there is a better way I'm missing.

$t=array_map(              # visit each array element and...
    filesize,              # map each filename to its filesize...
    $g=array_filter(       # using an array of...
        glob('*'),         # all files and directories...
        is_file            # filtered by files...
    )                      # 
);                         # 
asort($t);                 # sort the array of filesizes, then...
echo$g[key($t)];           # print element from the array of files using the first key of the sorted array as an index
\$\endgroup\$
2
\$\begingroup\$

Node.js (using walk), 114 bytes

Ignore newline:

require('walk').walk(__dirname).on('file',(r,s,n)=>
(m=s.size>m.size?m:s,n()),m=0).on('end',_=>console.log(m.name))

This invokes a walker that traverses through the current directory (__dirname) and for each file calls a function with its stat s and a function next n() that must be invoked to continue the traversal. Then at the end, it prints a filename with the minimum size in bytes found. s.size>m.size returns false when m.size is undefined, so after the first callback, m is equal to the first file found, and continues from there normally.

\$\endgroup\$
2
\$\begingroup\$

R, 36 bytes

x=file.info(y<-dir())$s;y[x==min(x)]

Explained

file.info() returns a data.frame of "file information" when given a character or character vector of file/folder names which when used on the list of files/folders in the current directory (dir()), looks something like:

                                                               size isdir mode               mtime               ctime               atime exe
Polyspace_Workspace                                               0  TRUE  777 2014-11-28 17:29:25 2014-11-28 17:29:25 2014-11-28 17:29:25  no
Python Scripts                                                    0  TRUE  777 2016-03-21 23:59:41 2016-03-21 23:59:41 2016-03-21 23:59:41  no
R                                                                 0  TRUE  777 2015-12-23 20:11:02 2015-12-23 20:11:02 2015-12-23 20:11:02  no
Rockstar Games                                                    0  TRUE  777 2015-04-14 12:23:05 2015-04-14 12:23:03 2015-04-14 12:23:05  no
TrackmaniaTurbo                                                   0  TRUE  777 2016-03-24 17:15:05 2016-03-24 13:13:48 2016-03-24 17:15:05  no
ts3_clientui-win64-1394624943-2014-06-11 03_18_47.004772.dmp 314197 FALSE  666 2014-06-11 02:18:47 2014-06-11 02:18:47 2014-06-11 02:18:47  no

Subsequently we just have the find the name of the file for which the size column (abbreviated using $s) is the smallest. Consequently, if there are more than one file with the smallest size, all will be returned.

Bonus: if we also wanted to disregard folders in the current directory we could simply search for size when isdir == FALSE: x=file.info(y<-dir());y[x$s==min(x$s[!x$i])] which turns out to be 44 bytes.

\$\endgroup\$
  • \$\begingroup\$ Bit late, but file.size is shorter because you don't have to do $s afterwards. \$\endgroup\$ – JAD Jun 23 '17 at 11:06
2
\$\begingroup\$

Tcl, 88 bytes

set s Inf
lmap f [glob -ty f *] {if [set m [file si $f]]<$s {set n $f
set s $m}}
puts $n

Try it online!

\$\endgroup\$
2
\$\begingroup\$

SmileBASIC, 110 bytes

DIM F$[0]FILES"TXT:",F$FOR I=0TO LEN(F$)-1F$[I][0]="TXT:
S=LEN(LOAD(F$[I],0))IF!Z||S<Z THEN Z=S:B=I
NEXT?F$[B]

Only looks at TXT: files, since DAT: files cannot be loaded unless you already know their size, making it impossible to load a random one.

\$\endgroup\$
  • \$\begingroup\$ How do you load a DAT: file? Could you brute-force every name/file size in the folder? \$\endgroup\$ – Pavel Jan 27 '17 at 22:38
  • \$\begingroup\$ Trying to load a 3-dimensional DAT: file into a 2-dimensional array (for example) will cause an error, so you can't brute force it. You just have to know the number of dimensions beforehand, which you normally would. \$\endgroup\$ – 12Me21 Jan 27 '17 at 22:41
  • \$\begingroup\$ Could you load a 2-d DAT: file into a 3-d array? Then you could create a maximum size array. And you can't catch errors in any way? \$\endgroup\$ – Pavel Jan 27 '17 at 22:43
  • \$\begingroup\$ Nope, that will cause a Type mismatch error. And there's no way to catch errors either. \$\endgroup\$ – 12Me21 Jan 27 '17 at 22:45
1
\$\begingroup\$

Groovy, 49 bytes

m={f->f.listFiles().sort{it.length()}[0].getName()}

Try it online!

Closure, usage: m(new File("location"))

\$\endgroup\$
1
\$\begingroup\$

C#, 277 bytes

Not the shortest, but what would you expect from C#?

Golfed

using System.Linq;using static System.IO.Directory;class P{static void Main(){var x=GetFiles(GetCurrentDirectory());var d=new long[]{}.ToList();foreach(var s in x){var b=new System.IO.FileInfo(s).Length;if(!d.Contains(b))d.Add(b);}System.Console.Write(x[d.IndexOf(d.Min())]);}}

Ungolfed

//Linq using for List.Min()
using System.Linq;
//Static using to save bytes on GetCurrentDirectory() and GetFiles()
using static System.IO.Directory;

class P
{
    static void Main()
    {
        //String array containing file paths
        var x = GetFiles(GetCurrentDirectory());
        //Creating a Long array and converting it to a list, less bytes than "new System.Collections.Generic.List<long>()"
        var d = new long[] { }.ToList();
        foreach (var s in x) //Loop through all file paths
        {
            //Getting file size in bytes
            var b = new System.IO.FileInfo(s).Length;
            if (!d.Contains(b))
                //If there isn't already a file with this size in our List, add the file path to list
                d.Add(b);

        }
        //Get index of the smallest Long in our List, which is also the index of the file path to the smallest file, then write that path
        System.Console.Write(x[d.IndexOf(d.Min())]);
    }
}
\$\endgroup\$
1
\$\begingroup\$

Röda, 32 31 bytes

{ls""|sort key=fileLength|pull}

It's an anonymous function that sorts the files in the current directory by file length and selects then the first file with pull.

Use it like this: main{ {ls""|sort key=fileLength|pull} }

\$\endgroup\$
  • \$\begingroup\$ Apparently ls"" works just as well as ls".". I think you can save a byte from that \$\endgroup\$ – Kritixi Lithos Mar 7 '17 at 18:30
  • \$\begingroup\$ @KritixiLithos It seems to. Thanks! \$\endgroup\$ – fergusq Mar 7 '17 at 18:35
0
\$\begingroup\$

SmileBASIC 3, 105 bytes (competing?)

Beats 12Me21's answer but still suffers from inability to load DAT files (which feels very cruel to be disqualifying considering the circumstances.)

DIM F$[0],T[0]FILES"TXT:",F$FOR I=0TO LEN(F$)-1F$[I][0]="TXT:
PUSH T,LEN(LOAD(F$[I]))NEXT
SORT T,F$?F$[0]

The shorter version above is annoying and prompts you on every file to load, but it does work. For two bytes more you can suppress the prompt; change line 2 to this:

PUSH T,LEN(LOAD(F$[I],0))NEXT
\$\endgroup\$
0
\$\begingroup\$

Batch File, 33 bytes

Batch files are moderately competitive this time, oddly enough.

@dir/os/b>..\q&set/pa=<..\q&"%a%.

Output

enter image description here


Find a way to stop the creation of q prior to dir/os/b being run and you'll save a maximum of 6 bytes by not needing to put the output file in a separate directory.

@dir/os/b>q&set/pa=<q&"%a%

Will always output q as the smallest file (unless tied for another 0 byte file) as it is created as an empty file before dir/b/os gathers a list of files.

\$\endgroup\$
0
\$\begingroup\$

C++17 (gcc), 180 bytes

#include<filesystem>
using namespace std::filesystem;auto f(){std::error_code e;path r;size_t m=-1,s;for(auto&p:directory_iterator(".")){s=file_size(p,e);if(s<m)m=s,r=p;}return r;}

Try it online!

Requires a recent standard library that implements std::filesystem.

\$\endgroup\$
0
\$\begingroup\$

Zsh, 18 14 bytes

echo *(DoL[1])

Try it online! Try it online!

  • (D) globs dotfiles
  • (oL) sorts by size
  • [1] selects the first match
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.