19
\$\begingroup\$

At runtime, keep prompting for a line of input until the user input is not the name of an existing file or directory or other file system item, relative to the current working directory. Then return/print that last inputted filename. You may assume that all user inputs will be valid filenames.

Pseudo-code 1

myform = new form("GUI")
myform.mytxt = new editfield("")
myform.ok = new button("OK")
repeat
  waitfor(myform.ok,"click")
until not filesystem.exists(myform.mytxt.content)
return(myform.mytxt.content)

Pseudo-code 2

LET TEXT = "."
WHILE HASFILE(TEXT) DO
  TEXT = PROMPT("")
ENDWHILE
RETURN TEXT

Examples of user input which will cause re-prompting when on TIO:

.
..
.env.tio
/
/bin/[
/lost+found

Examples of user input which will return when on TIO:

...
env.tio
../../bin/]
/lost/found
\$\endgroup\$
  • \$\begingroup\$ I'm fairly new to code golf here and can't seem to find any information on what counts as a solution. Do I need to include the main() function for languages that require it in a program, or can that be part of the header? Can import statements be a part of the header in TIO, or do they need to be part of the code and count against the byte count? For example, I have this solution: goo.gl/8RWNgu but not sure if it the bytes would be legitimate. \$\endgroup\$ – Makotosan Mar 16 '18 at 15:33
  • 2
    \$\begingroup\$ @Makotosan Both functions and full programs are fine, although in the case of functions they need to be reusable. Imports generally need to be included in the byte count. \$\endgroup\$ – Martin Ender Mar 16 '18 at 15:41

23 Answers 23

7
\$\begingroup\$

Batch, 37 bytes

@set/ps=
@if exist %s% %0
@echo %s%

(For some reason current Windows 10 CMD.EXE corrupts the title when it executes the %0.)

\$\endgroup\$
7
\$\begingroup\$

Mathematica, 33 28 bytes

f:=Input[]/._?FileExistsQ:>f

This assumes Mathematica's notebook environment where we can query input from the user with Input[]. The user input should be an actual string literal, so e.g. "ab/cd.ef" instead of just ab/cd.ef. The upside is that the input can be an arbitrary Mathematica expression that computes the input string.

This defines a symbol f which, when evaluated performs the required computation and ultimately evaluates to the first non-existent user input. It's essentially a nullary function, where we don't have to include ...[] to call it.

We can also save a bunch of bytes over a traditional If expression by making use of the pattern substitution operator /..

\$\endgroup\$
  • \$\begingroup\$ This fails if the user inputs the same thing twice \$\endgroup\$ – Lukas Lang Mar 15 '18 at 23:08
  • \$\begingroup\$ @Mathe172 Good catch, too bad, then I'll have to go with the boring loop. \$\endgroup\$ – Martin Ender Mar 15 '18 at 23:14
  • \$\begingroup\$ Turns out I don't, and it's even a byte shorter. :) \$\endgroup\$ – Martin Ender Mar 16 '18 at 0:16
7
\$\begingroup\$

Perl 5 -ln, 12 10 bytes

-2 bytes thanks to @DomHastings

#!/usr/bin/perl -ln
-e||1/!say

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ I think -e works without specifying $_, might not work for some cases though I guess... \$\endgroup\$ – Dom Hastings Mar 16 '18 at 10:17
  • \$\begingroup\$ @DomHastings Should work in all cases. It's documented that $_ is used when there is no argument to -e. \$\endgroup\$ – pipe Mar 16 '18 at 10:38
  • \$\begingroup\$ @DomHastings Thanks.For some reason I thought -e was an exception but of course it isn't \$\endgroup\$ – Ton Hospel Mar 16 '18 at 10:39
4
\$\begingroup\$

Bash, 29

read f
[ -e $f ]&&$0||echo $f
\$\endgroup\$
  • \$\begingroup\$ Why doesn't this work? \$\endgroup\$ – Adám Mar 15 '18 at 23:40
  • \$\begingroup\$ @Adám I'm not sure why it doesn't work in TIO. Suffice to say if you save it as a script file and run it, I think it works as expected \$\endgroup\$ – Digital Trauma Mar 16 '18 at 0:06
  • 1
    \$\begingroup\$ @Adám This works, the problem you had was that the program was trying to call .code.tio which contains the body of the script, but no information on how to run it. I'm not sure if there is a nice way to work around the shebang or this script needing to be in your path, though. \$\endgroup\$ – FryAmTheEggman Mar 16 '18 at 1:47
  • 2
    \$\begingroup\$ You can get around both (at the cost of two bytes) by changing $0 to . $0. Try it online!. Since . uses relative path names and the current shell. \$\endgroup\$ – Chris Mar 16 '18 at 7:20
  • 1
    \$\begingroup\$ What does it think of * as input? \$\endgroup\$ – Toby Speight May 21 '18 at 10:31
4
\$\begingroup\$

PowerShell 2 (through 6), 35 bytes

while(Test-Path($x=Read-Host)){};$x

Read-Host waits for input (if given a string as a parameter, uses the string as a prompt). If the provided input is a filename (or folder name) for one that exists, Test-Path returns $true, and the do-nothing block {} executes, and it re-prompts for input. If Test-Path returns $false because the input is not an extant file or folder, the do-nothing block does not execute, and the input name is printed.

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ – Martin Ender Mar 16 '18 at 19:46
  • \$\begingroup\$ You don't need the semi-colon after the {} to save a byte. \$\endgroup\$ – Veskah May 22 '18 at 22:23
  • \$\begingroup\$ @Veskah - I did in PS2, and it doesn't break PS3+ \$\endgroup\$ – Jeff Zeitlin May 23 '18 at 11:17
  • \$\begingroup\$ Ah, my bad. Didn't test it in 2. \$\endgroup\$ – Veskah May 23 '18 at 20:01
4
\$\begingroup\$

C (gcc), 62 bytes

main(){char b[99];while(scanf("%s",b)&&!access(b,0));puts(b);}

Try it online!

main(){
    char b[99]; // Declare buffer b
    while (scanf("%s",b)&&!access(b,0));    // Take one line of input, and test if file is accessible (exists)
    puts (b);   // If doesn't exist, loop ends and print file
}
\$\endgroup\$
  • \$\begingroup\$ Welcome to PPCG! You can use while(gets(b),!access(b,0)); to save 7 bytes. \$\endgroup\$ – Dennis May 21 '18 at 4:03
3
\$\begingroup\$

Funky, 40 bytes

tryfor)io.open(s=io.read())catchprint(s)

In true funky style, this uses keywords jammed against eachother, unmatching brackets and implicit keywords. Cleaned up, this looks like:

try{
    while(true){
        s = io.read()
        io.open(s)
    }
}catch(e){
    print(s)
}

Breakdown

try                                     // Try statement, this one is expected to fail.
   for)                                 // for) is a for loop with no arguments, which is functionally equivilent to a while(true) loop, much like for(;;)
       io.open(                         // Try to open a file relative to the CWD. If this fails to find a file, it will throw an error and escape the try/catch
               s=io.read()              // Read a line from STDIN and store it as s, this will still pass it to the arguments of the call.
                          )
                           catch        // When io.open fails
                                print(s)// Print out the last entered line.
\$\endgroup\$
3
\$\begingroup\$

Haskell, 76 bytes

import System.Directory
f=do x<-getLine;b<-doesPathExist x;last$pure x:[f|b]

Try it online!

Returns IO x where x is the inputted name of the file that does not exist.

Ungolfed

import System.Directory

insist = do { file <- getLine;
              exists <- doesPathExist file;
              if exists then insist else pure file }
\$\endgroup\$
3
\$\begingroup\$

R, 66 51 bytes

while((s=readline())%in%list.files(a=T)){};print(s)

-15 bytes thanks to plannapus

Runs a potentially infinite loop, where on each iteration

  1. A single line of user input is stored in the variable s
  2. We check if the input is in the list of filenames for the working directory (the a=T option for list.files() must be used to pick up things like ..)
  3. If s is in that list, we go to the next iteration; if not, we break the loop and print s.
\$\endgroup\$
  • \$\begingroup\$ How about shortening it to while((s=readline())%in%list.files(a=T)){};print(s)? \$\endgroup\$ – plannapus Mar 16 '18 at 13:06
  • \$\begingroup\$ @plannapus Great idea! Incorporated. \$\endgroup\$ – duckmayr Mar 16 '18 at 13:12
  • \$\begingroup\$ You're welcome. Also, I didn't think of it right away but functions list.files and dir are synonyms, so you can replace it with dir here. \$\endgroup\$ – plannapus Mar 16 '18 at 13:14
  • \$\begingroup\$ you could also replace readline() with scan(,'') \$\endgroup\$ – JAD Mar 16 '18 at 14:12
  • \$\begingroup\$ And print with cat \$\endgroup\$ – JAD Mar 16 '18 at 14:15
3
\$\begingroup\$

Python 3, 55 bytes

import glob
s="."
while glob.glob(s):s=input()
print(s)

Try it online!

-4 bytes thanks to ManfP
-6 bytes thanks to Rick Rongen

\$\endgroup\$
  • 2
    \$\begingroup\$ @Adám terrible misinterpretation, sorry \$\endgroup\$ – HyperNeutrino Mar 15 '18 at 22:57
  • \$\begingroup\$ You could replace the first input() with "." \$\endgroup\$ – ManfP Mar 15 '18 at 23:00
  • 1
    \$\begingroup\$ import os and os.path.exists is three bytes shorter. \$\endgroup\$ – Jonathan Allan Mar 16 '18 at 8:47
  • 1
    \$\begingroup\$ Rick Rongen suggested import glob and while glob.glob(s):... in an edit. \$\endgroup\$ – Martin Ender Mar 16 '18 at 9:59
  • \$\begingroup\$ @MartinEnder thanks for telling me :) \$\endgroup\$ – HyperNeutrino Mar 16 '18 at 15:13
3
\$\begingroup\$

C#, 101 bytes

()=>{var s="";try{for(;;System.IO.File.GetAttributes(s=System.Console.ReadLine()));}catch{}return s;}

For each of the 4 valid return values:

Ungolfed

() =>
{
    var s = "";
    try
    {
        for(;; System.IO.File.GetAttributes(s = System.Console.ReadLine()));
    }
    catch {}
    return s;
}

Explanation

relies on the fact that File.GetAttributes() throws an exception if file system object specified in its argument doesn't exist.

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

Powershell 3.0, 75 bytes

$x=1;while($x){$i=Read-Host;$x=Test-Path("$PSScriptRoot\$i")};Write-Host $i

First attempt; I'm sure there are a few optimizations I could make.

A slightly more readable form:

$x=1;                                                                       # Make sure we enter our while loop.
     while($x){                                                             # While we keep getting file names,                   
               $i=Read-Host;                                                # Get input from the user
                            $x=Test-Path("$PSScriptRoot\$i")};              # Combine our path with the user input, and see if it already exists.
                                                              Write-Host $i # Return the final (valid) file name.
\$\endgroup\$
  • \$\begingroup\$ Wouldn't it work even without $PSScriptRoot\? \$\endgroup\$ – Adám Mar 16 '18 at 6:46
  • \$\begingroup\$ Welcome to PPCG! A few quick golfs -- you can use a for loop instead, which allows you to move the initialization into the loop constructor for($x=1;$x){...}. Secondly, you can get rid of the Write-Host since there's an implicit Write-Output at program completion for anything left on the pipeline, so just leaving $i there will suffice. \$\endgroup\$ – AdmBorkBork Mar 16 '18 at 12:49
  • \$\begingroup\$ See my solution below; I've halved your byte count. \$\endgroup\$ – Jeff Zeitlin Mar 16 '18 at 19:38
  • \$\begingroup\$ @Adám: Maybe! I hadn't actually considered that. :P AdmBorkBork Thank you! I spent a long time lurking. Those are good ideas; the implicit output didn't even cross my mind... \$\endgroup\$ – Arkitekt Mar 17 '18 at 18:53
2
\$\begingroup\$

Java 9, 87 bytes

v->{String s;for(;new java.io.File(s=System.console().readLine()).exists(););return s;}

Ungolfed

TIO's JVM apparently has no system Console, so it's not testable there (see System.console()).

import java.util.function.*;
class Main {
  public static void main(String[] args) {
    Function<Void,String> f =


v->{
  String s;
  for(;new java.io.File(s=System.console().readLine()).exists(););
  return s;
}


;
    System.out.println(f.apply(null));
  }
}
\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 158 118 bytes

require('readline').createInterface({input:process.stdin}).on('line',s=>require('fs').existsSync(s)||--console.log(s))

Try it online!

Credit to @ConorO'Brien for coming up with shorter version. Inlined objects instead of using consts and utilizing error exit condition instead of explicitly exiting.

\$\endgroup\$
  • 1
    \$\begingroup\$ Nice answer so far, but there's room for potential. You can golf this approach in a few ways: you can omit both const, and you can also replace each variable with it's definition. Then, instead of using s=>{if(...){...}}, you could use s=>require('fs').existsSync(s)||process.exit(console.log(s)). Additionally, you can exit with an error, so you can write the lambda as s=>require('fs').existsSync(s)||--console.log(s). Try it online! \$\endgroup\$ – Conor O'Brien Mar 17 '18 at 2:02
  • \$\begingroup\$ Great ideas! Thanks! \$\endgroup\$ – Makotosan Mar 17 '18 at 3:59
1
\$\begingroup\$

Clean, 100 94 bytes

import System.IO,System.File
Start w#(s,w)=evalIO getLine w
#(b,w)=fileExists s w
|b=Start w=s

Try it online!

single-expression version:

import System.IO,System.File
Start w=(\(s,v)=(\(b,w)|b=Start w=s)(fileExists s v))(evalIO getLine w)

Try it online!

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

Perl 6, 39 bytes

my$f=".";while $f.IO.e {$f=get};say $f;

This works in the REPL, but it doesn't seem to work properly in TIO.

\$\endgroup\$
  • \$\begingroup\$ What about say first !*.IO.e,lines (23 bytes)? \$\endgroup\$ – nwellnhof Mar 17 '18 at 14:43
  • \$\begingroup\$ The above probably blocks indefinitely when run on the command line, but something like {}while ($_=get).IO.e;.say should work. \$\endgroup\$ – nwellnhof Mar 17 '18 at 15:03
1
\$\begingroup\$

PHP, 43 bytes

<?for(;file_exists($f=readline()););echo$f;

Run as CLI. Quite easy to understand.

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

Ruby, 40 39 37 bytes

{}while File.exist? gets.chomp
$><<$_

Try it online!

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

APL (Dyalog), 17 bytes

{⍞}⍣{~⎕NEXISTS⍺}⍬

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Returns the second non-existing input, (the_prev_wasnt_filename instead of env.tio). Change and then you can get rid of '.' too. \$\endgroup\$ – Adám Mar 16 '18 at 6:52
1
\$\begingroup\$

Kotlin, 67 bytes

val f={var s="."
while(java.io.File(s).exists()){s=readLine()!!}
s}

Try it online!

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

Attache, 35 bytes

{While[FileExists[x:=Prompt[]],0]x}

Try it online!

Alternative solutions

35 bytes: {If[FileExists[x:=Prompt[]],$[],x]}, recursive function.

37 bytes: {NestWhile[p:=Prompt,p[],FileExists]}, iterative function.

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

Min, 38 bytes

"." :a (a exists?) ("" ask @a) while a

Leaves last entered filename on the stack.

Explanation

"."         ; Put . on the stack. Every directory should contain this...
:a          ; Assign to a
(a exists?) ; A quot that checks if a exists in current directory
("" ask @a) ; Read line from stdin, assign to a
while       ; Do the second quote while the first leaves true on the stack
a           ; Leave a on the stack
\$\endgroup\$
0
\$\begingroup\$

SmileBASIC, 27 bytes

INPUT S$EXEC!CHKFILE(S$)?S$
\$\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.