29
\$\begingroup\$

In a single file, write a program that requires no input and produces no output. When run it should reverse the name of the file it is contained in, regardless of what the name is, without altering the code or producing other lasting side effects.

Any way of achieving this is fine. It only matters that once the program is run the only lasting change is that its file name has been reversed. e.g. no new files should be in the directory.

Running the program again should reverse the name back. Indeed, the program should be able to be run arbitrarily many times.

For the purposes of this challenge:

  • You may assume filenames are always strings of lowercase letters (a-z) between 1 and 127 characters long. (If your language requires files to have extensions to run then just reverse the part before the extension, e.g. mycode.batedocym.bat.)
  • You may assume the code file is in a directory by itself so it will not have naming conflicts (except with itself).
  • You may not assume the filename is not a palindrome, i.e. the same when reversed. Filenames that are palindromes should work just as well as those that aren't.
  • You may read your file's contents or metadata. There are no restrictions here.
  • You may assume your program will be run on a particular, modern, commonplace operating system (e.g. Windows/Linux), since not all shells have the same command set.

As a concrete example, say you have a Python program in a file called mycode in its own directory. Running

python mycode

in the terminal should result in the filename being reversed to edocym. The file edocym should be alone in its directory - no file named mycode should exist anymore. Running

python edocym

will reverse the name back to mycode, at which point the process can be repeated indefinitely.

If the same Python file was renamed racecar (without changing the code) and then run

python racecar

nothing should visibly change since "racecar" is a palindrome. That same goes if the filename were, say, a or xx.

The shortest code in bytes wins. Tiebreaker is higher voted answer.

\$\endgroup\$
7
  • \$\begingroup\$ Does the current working directory matter? \$\endgroup\$ Jun 11, 2016 at 2:11
  • \$\begingroup\$ @BradGilbertb2gills You should be able to copy the folder with the program to somewhere else and still have it work (assuming you have permissions and whatnot). You can assume the working directory of the shell will be the folder the file is in. \$\endgroup\$ Jun 11, 2016 at 3:30
  • 6
    \$\begingroup\$ What if we are using a compiled language? How does the executable affect your rules? \$\endgroup\$
    – EMBLEM
    Jun 11, 2016 at 5:39
  • \$\begingroup\$ Request to clarify 'accepts no input and produces no output'. Technically, the name of the file is an input that must ne retrieved from the file system and the changed name must be sent to the file system. These are input and output. It may be worthwhile to specify that no other outputs are allowed. \$\endgroup\$
    – atk
    Jun 13, 2016 at 0:14
  • \$\begingroup\$ Additionally, do you consider use of child processes to be violations of the input/output rules? That is, calling a separate process to perform part of the task, like reversing the name, would require sending the other process the name (output from your code and input to the app) and receive the value from the process (output of the process and input to the app). \$\endgroup\$
    – atk
    Jun 13, 2016 at 0:16

30 Answers 30

41
\$\begingroup\$

Bash + common linux utils, 13 bytes

My method is similar to @DigitalTrauma's but a bit shorter due to the pipe with ls:

mv * `ls|rev`
\$\endgroup\$
6
  • \$\begingroup\$ Oh - very good. \$\endgroup\$ Jun 11, 2016 at 4:58
  • 21
    \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! This is a very nice first answer. :) \$\endgroup\$
    – Alex A.
    Jun 11, 2016 at 5:17
  • 1
    \$\begingroup\$ Only works if there is no other file in the directory. \$\endgroup\$
    – WGroleau
    Jun 11, 2016 at 9:18
  • 2
    \$\begingroup\$ @WGroleau && terdon: both your comments are right but the question already handles those 2 assumptions. \$\endgroup\$ Jun 11, 2016 at 15:48
  • \$\begingroup\$ @JuliePelletier ah, yes, you're quite right. I missed that file names can only consist of lower case letters. \$\endgroup\$
    – terdon
    Jun 11, 2016 at 21:48
15
\$\begingroup\$

C#, 153 bytes

void f(){var x=System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name;File.Move(x,new string(x.Reverse().ToArray()).Substring(4)+".exe");}

OO is cool and all untill you have a variable defined:

System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name

thats just mean

\$\endgroup\$
13
\$\begingroup\$

Bash + common linux utils, 15

  • 1 byte saved thanks to @Dennis

Assumes that the script is in a directory by itself.

mv * `rev<<<$0`
\$\endgroup\$
3
  • 7
    \$\begingroup\$ You may assume the code file is in a directory by itself, so $0 can be replaced with *. \$\endgroup\$
    – Dennis
    Jun 11, 2016 at 1:04
  • \$\begingroup\$ Sorry but there's a small bug in your update and it doesn't work as is. The simplest fix is to go back closer to what you had before with $0 instead of the last *. \$\endgroup\$ Jun 11, 2016 at 4:02
  • 1
    \$\begingroup\$ @JuliePelletier It seemed to work before when I tried it, but yes, you're right - * globbing expansion doesn't happen to the right of a <<<. \$\endgroup\$ Jun 11, 2016 at 4:57
7
\$\begingroup\$

Julia, 51 bytes

d,f=splitdir(@__FILE__)
cd(d)do
mv(f,reverse(f))end

This program should be operating system agnostic, though it was only tested on OS X.

Ungolfed:

# Get the directory and file name of the current source file
d, f = splitdir(@__FILE__)

# Change the working directory temporarily to d
cd(d) do
    # Overwrite the file with the reverse of its name
    mv(f, reverse(f))
end
\$\endgroup\$
2
  • 8
    \$\begingroup\$ Congrats! 20k!!! \$\endgroup\$
    – Luis Mendo
    Jun 11, 2016 at 1:10
  • \$\begingroup\$ Most answers seem to assume that the file is in the current directory, so I don't think you need the cd. In this case f=readdir()[] would be even shorter. \$\endgroup\$
    – Dennis
    Jun 12, 2016 at 18:36
7
\$\begingroup\$

MATLAB, 50 46 bytes

e='.m';x=mfilename;movefile([x e],[flip(x) e])

Thanks to @Suever for removing 4 bytes and for the testing!

Tested on OS X El Capitan and Debian Jessie, both with Matlab version R2014a.

On Windows a flag 'f' is needed ( e='.m';x=mfilename;movefile([x e],[flip(x) e]),'f') to change file name while the file is being used.

How it works

e='.m';                       % Store file extension '.m' in variable `e`
x=mfilename;                  % Get name of file being run, without the extension
movefile([x e],[flip(x) e])   % Move (rename) file. `flip` is used for reversing the
                              % name without extension. [...] is (string) concatenation
\$\endgroup\$
6
  • \$\begingroup\$ What OS are you on that the 'f' is required? \$\endgroup\$
    – Suever
    Jun 11, 2016 at 1:00
  • \$\begingroup\$ @Suever Windows. Isn't it needed on Mac? \$\endgroup\$
    – Luis Mendo
    Jun 11, 2016 at 1:09
  • \$\begingroup\$ Not needed on Mac of Linux it seems. \$\endgroup\$
    – Suever
    Jun 11, 2016 at 1:10
  • \$\begingroup\$ @Suever Thanks! 4 bytes off :-) \$\endgroup\$
    – Luis Mendo
    Jun 11, 2016 at 1:11
  • \$\begingroup\$ @Suever Can you indicate the exact OS this works on? \$\endgroup\$
    – Luis Mendo
    Jun 11, 2016 at 1:12
5
\$\begingroup\$

Batch, 109 bytes

@echo off
set f=%0
set r=
:l
set r=%f:~0,1%%r%
set f=%f:~1%
if not .%f%==. goto l
ren %0.bat %r%.bat

Note 1: Batch files must end in .bat; it is assumed that the batch file is executed by its name without extension, and that the .bat is not to be reversed. For example, reverse would attempt to rename reverse.bat to esrever.bat.
Note 2: CMD.EXE errors out after renaming the batch file. (COMMAND.COM wouldn't, except that it's incapable of string manipulation in the first place.)

Edit: Saved 2 bytes by using the guarantee that the file name is alphabetic (based on @CᴏɴᴏʀO'Bʀɪᴇɴ's comment).

\$\endgroup\$
3
  • 4
    \$\begingroup\$ 1. WHY AREN'T YOU SHOUTING? 2. I think you can save a byte by doing if ]%f% NEQ ] goto l \$\endgroup\$ Jun 11, 2016 at 1:36
  • \$\begingroup\$ @CᴏɴᴏʀO'Bʀɪᴇɴ Ah yes, the file name is alphabetic, so I can in fact save 2 bytes, but thanks for the hint. \$\endgroup\$
    – Neil
    Jun 11, 2016 at 10:31
  • 2
    \$\begingroup\$ YOU NEED TO SHOUT IN BATCH UNLESS YOU ARE USING OOBL AKA SMALLTALK-80 \$\endgroup\$
    – cat
    Jun 11, 2016 at 13:23
5
\$\begingroup\$

C, 102 bytes

main(c,v)char**v;{char*b=strdup(*v),*n=strrchr(*v,47),*t=strchr(b,0);for(;*++n;*--t=*n);rename(*v,b);}

Breakdown:

                            // No #include lines required (for GCC at least)
main(c,v)char**v;{          // K&R style function to save 2 bytes
    char*b=strdup(*v),      // Duplicate args[0] (script path)
        *n=strrchr(*v,47),  // Find last "/" in input
        *t=strchr(b,0);     // Go to end of output string
    for(;*++n;*--t=*n);     // Reverse input into output character-by-character
    rename(*v,b);           // Rename the file
}                           // Implicit return 0

Finally a challenge where C isn't (quite so hopelessly) uncompetitive!


If we take "You can assume the working directory of the shell will be the folder the file is in" to mean that the program will always be invoked as ./myexecutable, we can simplify *n=strrchr(*v,47) to *n=*v+1 to save 10 characters, but this isn't entirely valid (it could be invoked as ././myexecutable, for example).


Also if you want to keep a file extension (e.g. ".out") in-tact, you can change *t=strchr(b,0) to *t=strrchr(b,46), costing 2 bytes. Not required though.

\$\endgroup\$
6
  • \$\begingroup\$ Nice - I'd never looked to see what rename does if src==dest; it appears you satisfy the palindrome constraint for free. \$\endgroup\$ Jun 15, 2016 at 13:27
  • \$\begingroup\$ Note that this requires a file system where codepoint 47 is the separator. I think this includes POSIX (or does that allow EBCDIC / in a corner case?) \$\endgroup\$ Jun 15, 2016 at 13:30
  • \$\begingroup\$ @TobySpeight yeah I checked gnu.org/software/libc/manual/html_node/Renaming-Files.html for some clarification, but the closest I found was "One special case for rename is when oldname and newname are two names for the same file. The consistent way to handle this case is to delete oldname. However, in this case POSIX requires that rename do nothing and report success—which is inconsistent. We don’t know what your operating system will do.", so I guess there's an outside chance it will just delete the file on non-POSIX compliant systems. So yeah, real code should check! \$\endgroup\$
    – Dave
    Jun 15, 2016 at 17:26
  • \$\begingroup\$ I just checked linux.die.net/man/3/rename and it confirms that Linux handles it POSIX compliantly: "If the old argument and the new argument resolve to the same existing file, rename() shall return successfully and perform no other action." \$\endgroup\$
    – Dave
    Jun 15, 2016 at 17:30
  • \$\begingroup\$ I was going with the Debian manpage: "If oldpath and newpath are existing hard links referring to the same file, then rename() does nothing, and returns a success status" - if the strings are identical, they refer to the same file. \$\endgroup\$ Jun 15, 2016 at 17:48
4
\$\begingroup\$

Ruby, 24 bytes

File.rename$0,$0.reverse

Fairly self-explanatory. ($0 is the name of the file being executed.)

Run with ruby whatever with a working directory of the directory that contains the file.

\$\endgroup\$
3
\$\begingroup\$

Vitsy + *sh, 15 bytes

iG:`?r.iG' mr',

Explanation

iG:`?r.iG' mr',
i               Push -1 to the stack. (this assumes that no arguments are passed)
 G              Get the use name of the class specified by the top item of the
                stack. (-1 refers to the origin class, so this class)
  :             Duplicate stack and jump to it.
   `            Read a file with the current stack as its name, replacing the stack
                with the file's contents.
    ?           Shift one stack to the right.
     r          Reverse the current stack.
      .         Write a file with the name specified by the top stack and the
                contents as the second-to-top stack.
       iG       Get the name of the current class again.
         ' mr'  Push 'rm ' to the stack.
              , Execute the current stack as a command.

Note that this submission must use the non-safe version of Vitsy (cannot be done on Try It Online!)

\$\endgroup\$
3
\$\begingroup\$

Perl 5, 18 bytes

A bit like the Ruby one (run perl nameofscript):

rename$0,reverse$0

Taking a possible path into account is uglier (47 bytes)

($a,$b)=$0=~/(.*\/)?(.*)/;rename$0,$a.reverse$b
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Hello, and welcome to PPCG! Great first post! \$\endgroup\$ Jun 12, 2016 at 15:08
2
\$\begingroup\$

V, 29 26 bytes

:se ri
izyw:!mv z "
dd

Since this contains unprintables, here is a hex dump:

00000000: 3a73 6520 7269 0a69 127a 1b79 773a 216d  :se ri.i.z.yw:!m
00000010: 7620 127a 2012 220a 6464                 v .z .".dd

Note: this will not run on v.tryitonline.net since TIO does not allow file access.

Explanation:

:se ri            "Turn on 'reverse mode' (all text is inserted backwards)
i<C-r>z<esc>      "Enter the path to the file in reverse
yw                "Yank a word. This first word is the name we will save the new file as

"Run an "mv" in the terminal with the contents of register 'z' (the path to the file)
"And the contents of register '"' (the word we yanked)
:!mv <C-r>z <C-r>"

dd                "Delete a line so that we don't have any text printed.
\$\endgroup\$
2
\$\begingroup\$

Python 3, 105 bytes

import os;a=__file__.split('\\')[::-1][0].split('.');os.rename('.'.join(a),'.'.join([a[0][::-1],a[1]]))

-Alex.A removed 1 byte.

-Digital Trauma showed me os.rename() which took away 62 bytes.

-muddyfish removed 7 bytes.

\$\endgroup\$
8
  • \$\begingroup\$ I think you can save a byte by removing the space after the comma in the import \$\endgroup\$
    – Alex A.
    Jun 11, 2016 at 1:40
  • \$\begingroup\$ import os,sys;f=sys.argv[0];os.rename(f,f[::-1]) should do the trick for 48 bytes \$\endgroup\$ Jun 11, 2016 at 2:01
  • \$\begingroup\$ doing f[::-1] reverses not only the file name, but the entire path. However, thanks for introducing me to the os.rename() feature. \$\endgroup\$
    – Magenta
    Jun 11, 2016 at 4:00
  • \$\begingroup\$ @Magenta For me, sys.argv[0] just returns the filename only without the path when the script is run in its own directly. Helka indicated this is ok \$\endgroup\$ Jun 11, 2016 at 5:01
  • 1
    \$\begingroup\$ You can simply do without the .py extension. Python doesn't need it if called explicitly with the interpreter: "python mygolf" is fine; "python mygolf.py" is not necessary \$\endgroup\$ Jun 11, 2016 at 23:10
2
\$\begingroup\$

PHP, 84, 70, 54 bytes

rename($f=__FILE__,strrev(basename($f,$e='.php')).$e);


EDIT: removed 14 bytes thanks to insertusernamehere in the comments
EDIT: removed 16 bytes thanks to Martijn in the comments

\$\endgroup\$
7
  • 2
    \$\begingroup\$ You can get it down to 70 bytes: rename($f=__FILE__,__DIR__."/".strrev(pathinfo($f)[filename]).".php");. \$\endgroup\$ Jun 11, 2016 at 6:35
  • \$\begingroup\$ Excelent!!! but your code it's better, wow you got 31 bytes \$\endgroup\$
    – tttony
    Jun 13, 2016 at 1:18
  • \$\begingroup\$ Can't you make it relative? WOuld save 7 bytes: rename($f=__FILE__,"./".strrev(pathinfo($f)[filename]).".php"); \$\endgroup\$
    – Martijn
    Jun 13, 2016 at 11:48
  • \$\begingroup\$ or even smaller: rename(__FILE__,strrev(basename(__FILE__,'.php')).'.php'); \$\endgroup\$
    – Martijn
    Jun 13, 2016 at 12:03
  • \$\begingroup\$ Cool! Adding vars I got now 54 bytes \$\endgroup\$
    – tttony
    Jun 13, 2016 at 15:44
2
\$\begingroup\$

PowerShell, 39 bytes

mi *(-join((ls).name)[-5..-999]+'.ps1')
\$\endgroup\$
1
  • \$\begingroup\$ Hi, and welcome to PPCG! Nice first post! \$\endgroup\$
    – Riker
    Jul 23, 2016 at 16:36
2
\$\begingroup\$

Python 2, 41 bytes

import os;s=__file__;os.rename(s,s[::-1])

Demo on Bash.

Python really doesn't care the file extension, so we can just flip the entire file name.

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

PHP, 31 bytes

Nothing much to explain I guess:

rename($x=$argv[0],strrev($x));
\$\endgroup\$
1
\$\begingroup\$

Perl 6,  70  27 bytes

If it needed to work in a different working directory you would need something like this:

$_=$*PROGRAM;.rename: .basename.flip.IO.absolute: .absolute.IO.dirname

Since the working directory will be the same directory as the program it can be simplified to just:

$_=$*PROGRAM;.rename: .flip

Explanation:

$_ = $*PROGRAM;  # IO::Path object

$_.rename:
    $_.basename
      .flip      # reverse characters
      .IO        # turn into an IO object (IO::Path)
      .absolute: # turn it into an absolute path Str in the following dir
        $_.absolute.IO.dirname
\$\endgroup\$
1
\$\begingroup\$

JavaScript (Node), 108 104 68 bytes

36 bytes saved, thanks to Downgoat!

Windows version:

require("fs").rename(F=__filename,F.split(/.*\\|/).reverse().join``)

Other version:

require("fs").rename(F=__filename,F.split(/.*\/|/).reverse().join``)
\$\endgroup\$
1
  • \$\begingroup\$ @Upgoat I don't need to, I don't think. I'm matching js at the end of the filepath, preceded by a character. This will always be a .. \$\endgroup\$ Jun 11, 2016 at 2:07
1
\$\begingroup\$

JavaScript ES6 (Node.js) 70 Bytes

No Regex Yay!

require("fs").rename(a=__filename,[...a].reverse().join``.split`/`[0])

Any help is appreciated

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

PowerShell v4+, 68 bytes

$a,$b=($c=(ls).Name)-split'\.';mv $c "$(-join($a[$a.length..0])).$b"

Only works because the script is guaranteed to be in a directory all by itself. Performs an ls (alias for Get-ChildItem) and takes the .Name of the resultant object(s). We store that in $c and then -split it on literal period to get the filename and extension, and store those in $a and $b, respectively.

Next is the mv (alias for Move-Item) command, where we're moving $c to $a(reversed).$b.

Example

PS C:\Tools\Scripts\golfing\reverse> ls

    Directory: C:\Tools\Scripts\golfing\reverse

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         6/13/2016   7:58 AM         88 reverse.ps1

PS C:\Tools\Scripts\golfing\reverse> .\reverse.ps1

PS C:\Tools\Scripts\golfing\reverse> ls

    Directory: C:\Tools\Scripts\golfing\reverse

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         6/13/2016   7:58 AM         88 esrever.ps1
\$\endgroup\$
1
\$\begingroup\$

Python (2.7 or 3.4+), 61 49 bytes

I believe this is close to the optimal Python solution:

import os;a=__file__;os.rename(a,a[-4::-1]+".py")

Inspired by s4b3r6's answer, but uses list slicing instead of reverse, and saves __file__ to a variable to save bytes when using it twice.

Note: This assumes that the filename is always *.py. A slightly more generic solution that can handle any two-character file extension would be to use a[-3:] to replace ".py", at the cost of 1 extra byte.

Update: Saved 12 bytes by using the list slicing trick a[-4::-1] to remove the file extension, instead of splitting and then reversing with a.split(".")[0][::-1].

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

Powershell, 112 bytes

I'm not going to beat the unix cmds, just adding my two pence for fun :-)

gci * | % { $n=($_.basename[-1..-(($_.basename).length)] -join “”)+$_.Extension; mv -Path $_.Fullname -Dest $n }
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to PPCG! We require that answers display their score, so I've edited it in for you. Also, you can format your code by highlighting it and selecting the button that looks like brackets {}, or by adding 4 spaces before your code. \$\endgroup\$ Jul 5, 2016 at 13:45
0
\$\begingroup\$

PowerShell, 50 bytes

mv *(-join($f=(ls).BaseName)[$f.Length..0]+'.ps1')

There is only one file, so mv * shell wildcard will only have one result. The destination name is (ls).basename which lists all the files (alias for 'dir'), calls for the BaseName property - and since there's only one file, PowerShell will unpack the 1-item array into a string. Store that filename in $f, then index it with a countdown and -join the reversed characters back up into a string. Add the mandatory .ps1 suffix.

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

AutoIt, 45 bytes

$a=@ScriptName
FileMove($a,StringReverse($a))
\$\endgroup\$
0
\$\begingroup\$

Python 2.7, 68 bytes

import os;a=__file__;os.rename(a,a.split("\\")[-1][:-3][::-1]+".py")

This is probably the best I can get it. I just proved myself wrong.

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

Python (2 & 3), 88 78 bytes

import os;os.rename(__file__,''.join(reversed(__file__.split(".")[0]))+".py"))

Exploits the fact that the filename is given by sys.argv (as the working directory is the folder the file is in), and makes use of os.rename. Annoyingly, reversed returns an iterator, so we have to use join.

Edit: Saved 10 bytes by using __file__ instead of sys.argv[0], as suggested by @muddyfish to @DigitalTrauma.

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

tcl, 42

file rename $argv0 [string reverse $argv0]
\$\endgroup\$
0
\$\begingroup\$

Visual Basic Script, 44 Bytes

WScript.Echo(StrReverse(WScript.ScriptName))

Example output for file called reverse.vbs (Run with cscript):

sbv.esrever
\$\endgroup\$
0
\$\begingroup\$

sfk, 83 bytes

list -maxfiles=1 . +setvar n +getvar n +swap +setvar m +ren -var . /#(n)/#(m)/ -yes

Try it online!

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

SmileBASIC 60 bytes

P$=PRGNAME$()FOR I=1-LEN(P$)TO.Q$=Q$+P$[-I]NEXT
RENAME P$,Q$

Alternative:

P$=PRGNAME$()T$=P$*1WHILE""<T$Q$=Q$+POP(T$)WEND
RENAME P$,Q$
\$\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.