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\$
2
  • \$\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, 2018 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\$ Mar 16, 2018 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\$
0
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\$
3
  • \$\begingroup\$ This fails if the user inputs the same thing twice \$\endgroup\$
    – Lukas Lang
    Mar 15, 2018 at 23:08
  • \$\begingroup\$ @Mathe172 Good catch, too bad, then I'll have to go with the boring loop. \$\endgroup\$ Mar 15, 2018 at 23:14
  • \$\begingroup\$ Turns out I don't, and it's even a byte shorter. :) \$\endgroup\$ Mar 16, 2018 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\$
3
  • 1
    \$\begingroup\$ I think -e works without specifying $_, might not work for some cases though I guess... \$\endgroup\$ Mar 16, 2018 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, 2018 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, 2018 at 10:39
4
\$\begingroup\$

Bash, 29

read f
[ -e $f ]&&$0||echo $f
\$\endgroup\$
5
  • \$\begingroup\$ Why doesn't this work? \$\endgroup\$
    – Adám
    Mar 15, 2018 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\$ Mar 16, 2018 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\$ Mar 16, 2018 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, 2018 at 7:20
  • 1
    \$\begingroup\$ What does it think of * as input? \$\endgroup\$ May 21, 2018 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\$
4
  • 1
    \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ Mar 16, 2018 at 19:46
  • \$\begingroup\$ You don't need the semi-colon after the {} to save a byte. \$\endgroup\$
    – Veskah
    May 22, 2018 at 22:23
  • \$\begingroup\$ @Veskah - I did in PS2, and it doesn't break PS3+ \$\endgroup\$ May 23, 2018 at 11:17
  • \$\begingroup\$ Ah, my bad. Didn't test it in 2. \$\endgroup\$
    – Veskah
    May 23, 2018 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\$
1
  • \$\begingroup\$ Welcome to PPCG! You can use while(gets(b),!access(b,0)); to save 7 bytes. \$\endgroup\$
    – Dennis
    May 21, 2018 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\$
6
  • \$\begingroup\$ How about shortening it to while((s=readline())%in%list.files(a=T)){};print(s)? \$\endgroup\$
    – plannapus
    Mar 16, 2018 at 13:06
  • \$\begingroup\$ @plannapus Great idea! Incorporated. \$\endgroup\$
    – duckmayr
    Mar 16, 2018 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, 2018 at 13:14
  • \$\begingroup\$ you could also replace readline() with scan(,'') \$\endgroup\$
    – JAD
    Mar 16, 2018 at 14:12
  • \$\begingroup\$ And print with cat \$\endgroup\$
    – JAD
    Mar 16, 2018 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\$
6
  • 2
    \$\begingroup\$ @Adám terrible misinterpretation, sorry \$\endgroup\$
    – hyper-neutrino
    Mar 15, 2018 at 22:57
  • \$\begingroup\$ You could replace the first input() with "." \$\endgroup\$
    – ManfP
    Mar 15, 2018 at 23:00
  • 1
    \$\begingroup\$ import os and os.path.exists is three bytes shorter. \$\endgroup\$ Mar 16, 2018 at 8:47
  • 1
    \$\begingroup\$ Rick Rongen suggested import glob and while glob.glob(s):... in an edit. \$\endgroup\$ Mar 16, 2018 at 9:59
  • \$\begingroup\$ @MartinEnder thanks for telling me :) \$\endgroup\$
    – hyper-neutrino
    Mar 16, 2018 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\$
0
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\$
4
  • \$\begingroup\$ Wouldn't it work even without $PSScriptRoot\? \$\endgroup\$
    – Adám
    Mar 16, 2018 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\$ Mar 16, 2018 at 12:49
  • \$\begingroup\$ See my solution below; I've halved your byte count. \$\endgroup\$ Mar 16, 2018 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, 2018 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\$
0
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\$
2
  • 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\$ Mar 17, 2018 at 2:02
  • \$\begingroup\$ Great ideas! Thanks! \$\endgroup\$
    – Makotosan
    Mar 17, 2018 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\$
2
  • \$\begingroup\$ What about say first !*.IO.e,lines (23 bytes)? \$\endgroup\$
    – nwellnhof
    Mar 17, 2018 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, 2018 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\$
1
  • \$\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, 2018 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 and acknowledge you have read our privacy policy.

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