110

For those out of the loop, sl is a humourous command line tool that is meant to trip people up if they mistype ls. When invoked it prints a Steam Locomotive. For example:

                          (  ) (@@) ( )  (@)  ()    @@    O     @     O     @      O
                     (@@@)
                 (    )
              (@@@@)

            (   )
         ====        ________                ___________
     _D _|  |_______/        \__I_I_____===__|_________|
      |(_)---  |   H\________/ |   |        =|___ ___|      _________________
      /     |  |   H  |  |     |   |         ||_| |_||     _|                \_____A
     |      |  |   H  |__--------------------| [___] |   =|                        |
     | ________|___H__/__|_____/[][]~\_______|       |   -|                        |
     |/ |   |-----------I_____I [][] []  D   |=======|____|________________________|_
   __/ =| o |=-O=====O=====O=====O \ ____Y___________|__|__________________________|_
    |/-=|___|=    ||    ||    ||    |_____/~\___/          |_D__D__D_|  |_D__D__D_|
     \_/      \__/  \__/  \__/  \__/      \_/               \_/   \_/    \_/   \_/

However, in the man page for sl, it states the following bug:

BUGS
        It rarely shows contents of current directory.

So, the question remains, are there some conditions, under which sl actually does show the current directory?

Braiam
  • 35,991

10 Answers10

193

As far as I know, the only condition under which sl shows the current directory is when you mistype it as ls.

slm
  • 369,824
sfyn
  • 1,727
41
  • Lemma: sl prints a steam locomotive
  • Lemma: Valid file names cannot contain forward slashes (although paths can)
  • Lemma: The steam locomotive contains forward slashes:

    $ touch '                          (  ) (@@) ( )  (@)  ()    @@    O     @     O     @      O
    >                      (@@@)
    >                  (    )
    >               (@@@@)
    > 
    >             (   )
    >          ====        ________                ___________
    >      _D _|  |_______/        \__I_I_____===__|_________|
    >       |(_)---  |   H\________/ |   |        =|___ ___|      _________________
    >       /     |  |   H  |  |     |   |         ||_| |_||     _|                \_____A
    >      |      |  |   H  |__--------------------| [___] |   =|                        |
    >      | ________|___H__/__|_____/[][]~\_______|       |   -|                        |
    >      |/ |   |-----------I_____I [][] []  D   |=======|____|________________________|_
    >    __/ =| o |=-O=====O=====O=====O \ ____Y___________|__|__________________________|_
    >     |/-=|___|=    ||    ||    ||    |_____/~\___/          |_D__D__D_|  |_D__D__D_|
    >      \_/      \__/  \__/  \__/  \__/      \_/               \_/   \_/    \_/   \_/'
    touch: cannot touch ‘[...]’: No such file or directory
    

Conclusion: sl never shows the current directory. QED.

l0b0
  • 51,350
  • Why is it not a valid file name? Too long? – gerrit Apr 15 '14 at 14:13
  • 6
    It contains several /'es, which are not allowed in Unix filenames. – mtak Apr 15 '14 at 15:03
  • You could always create the intermediate directories -- but then it wouldn't be showing (just) the contents of the current directory. – Keith Thompson Apr 15 '14 at 18:50
  • 2
    If you did a mkdir -p "$(dirname "$(sl)")" you could do touch "$(sl)". Of course, you might be testing the limits of your OS/FS. And have fun cleaning that up. – Kevin Apr 15 '14 at 18:51
  • I don't know if this counts, but there have been buggy programs that allowed you to rename a file to one with slashes in. Konqueror 3 comes to mind. Then you could have files with those exact names. – Mr Lister Apr 16 '14 at 07:09
  • 3
    @MrLister Surely that would only be possible if the filesystem also had a bug in it to allow such files to be created. Do you have a reference? – l0b0 Apr 16 '14 at 07:17
  • That's the first time I see something useful in Windows using backslash as path separator... Can we run it under Windows? Ohh... just seeing that it also contains \ ... </enthusiastic mode> – Volker Siegel Apr 16 '14 at 22:48
  • 2
    @VolkerSiegel: Not really. Windows supports both / and \, and they mean the same thing. – 0.. Apr 17 '14 at 09:38
  • @xfix But, can they both be used in filenames then, if escaped in some way? To contradict the proof above, we need to use the whole multiline train as a filename, but that contains / and \ - I have not much hope left that Windows supports both as part of a plain file name :) I shoud just accept the proof, maybe! – Volker Siegel Apr 17 '14 at 09:46
  • @VolkerSiegel: No, they cannot be used in file names. c:\windows/system32\notepad.exe is perfectly fine path in Windows. – 0.. Apr 17 '14 at 09:48
  • On OS X, you can get the Finder to show you "filenames" with slashes in them. They really contain colons (:), which were directory separators in the ancestors of OS X; the Finder visualizes them as slashes. – alexis Apr 17 '14 at 11:12
  • 3
    If you have a file called H (for instance), then sl does indeed show it. It's just that it also shows a lot of other things. :-) – ShreevatsaR Apr 20 '14 at 12:52
  • @Kevin i tried it: mkdir: cannot create directory ‘\033[?1049h\033[1;33r\033[m\033(B\033[4l\ [many many bytes] 033[1P\n\033[1P\n\033[1P\n \033[1K\r\033[1P\n\033[1P\n\033[1P\n\033[1P\n=| o |=-~~\\ ’: File name too long. So at least on btrfs it doesn't work. – user371366 Aug 25 '17 at 16:43
  • oh yikes, before it gave up though it did create a pretty deep tree! – user371366 Aug 25 '17 at 16:58
37

Here's a patch to fix that bug :)

diff --git a/sl.c b/sl.c
index 2eeceb3..f2213ad 100644
--- a/sl.c
+++ b/sl.c
@@ -37,6 +37,7 @@
 #include <curses.h>
 #include <signal.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include "sl.h"

 int ACCIDENT  = 0;
@@ -71,6 +72,13 @@ void option(char *str)
 int main(int argc, char *argv[])
 {
     int x, i;
+    
+    srand(time(NULL));
+    if(rand() % 100 < 10)
+    {
+       /* 10% chance of directory listing :) */
+       execv("/bin/ls", argv);
+    }

     for (i = 1; i < argc; ++i) {
    if (*argv[i] == '-') {
devnull
  • 10,691
  • 5
    Oh lord. You sir are a scholar and a genius. –  Apr 16 '14 at 02:57
  • 3
  • 1
    Y'know, I actually have no idea how to do that? I don't use github myself except as a web-based download portal for other people's software. You can do that if you like. I officially disclaim all copyright on the above code and place it in the public domain. – Ionoclast Brigham Apr 16 '14 at 03:57
  • +1, but that's not exactly 10% - rand() "Returns a pseudo-random integral number in the range between 0 and RAND_MAX," which is library-dependent but may not be divisible by 100. – l0b0 Apr 16 '14 at 07:19
  • @devnull, your edit is wrong: exit is unreachable (no fork). @l0b0, that's the point of the modulo. The link you provided yourself uses the exact same example: there is a 10% chance of getting 0-9 (< 10) out of the 0-99 (% 100) range provided the distribution is uniform. Why am I doing this. – tne Apr 16 '14 at 13:17
  • @tne You are right; rolling back. – devnull Apr 16 '14 at 13:18
  • 1
    Technically, execx() functions can return. From man 3 exec: "If any of the exec() functions returns, an error will have occurred. The return value is -1, and the global variable errno will be set to indicate the error." – Ionoclast Brigham Apr 16 '14 at 16:40
  • Of course, if execv("/bin/ls", argv) fails, you've got bigger problems than seeing a steam locomotive you weren't expecting. – Ionoclast Brigham Apr 16 '14 at 16:42
  • @tne The modulo doesn't solve that. For example, if you use a rand() which returns a number between 0 and 109, there's an almost 2% chance of rand() % 100 < 10. With a minimum range of 32767 the difference is pretty small, but not zero. – l0b0 Apr 16 '14 at 22:29
  • @l0b0 I think you mean 20%? 2/11 == 0.181818... But yes, point taken. The actual chance of getting less than ten back from the modulo is more like 0.1 + (10/67)*(67/32768) ~= 10.03% if rand is returning a non-negative signed short with something approximating a uniform random distribution. – Ionoclast Brigham Apr 16 '14 at 23:00
  • @lonoclast Brigham: You're entirely right. I think it's about time the sl project had its own flame war about whether it should fallback to the train behavior or error-out if ls can't be found/executed for whatever reason :). @l0b0: I stand corrected, you were one step ahead of me the whole time. (I actually misread your "library-independent" sentence; didn't realize you were talking about RAND_MAX and thought you were talking about the result for some reason, which is why it sounded so weird.) It's been a good run guys, but I hereby resign from the project. Too many disagreements. – tne Apr 17 '14 at 07:42
24

You can check the source code here - https://github.com/mtoyoda/sl, alas there is no other options other than the ones documented and sadly nothing that will actually print the names of files.

So it looks like @sfyn's answer is the correct one.

Graeme
  • 34,027
13

Note that I0b0's answer is only a proof that sl will never display all and only the current directory listing. However, there are circumstances in which sl will display the current directory listing together with additional 'information'.

For example, in an empty directory:

$ touch '                          (  ) (@@) ( )  (@)  ()    @@    O     @     O     @      O'
$ touch '                   (@@@)'
$ touch '                  (    )'
$ touch '              (@@@@)'
$ touch '            (   )'
$ sl

will on the first six lines list the contents of the directory, and on the remaining 10 lines will conveniently embellish this listing with an image of a train (without smoke).

J.P.
  • 231
  • 3
    Or, the current directory could be an empty set. In which case all the (non-existent) files are displayed along with a picture of a train. :-) – Kevin Seifert Nov 17 '15 at 17:49
8

I know that Lego Stormtroopr has logged a ticket so that the critical issue can be addressed. Who knows much time it might take for a fix to be rolled out?

As such, I've provided a workaround so that the impact due to the grave issue is minimized. You can create a shell function sl that would execute sl:

sl() {
  ((RANDOM%42)) && command sl || ls;
}

Now invoking sl will, sporadically, list the directory contents.

devnull
  • 10,691
2

If you alias it to ls, it'll print the current directory - in fact, once I stopped laughing at the steam engine locomotive, I added that to my list of aliases.

1

Yes, sl will act just like ls if you set up the appropriate alias in bash or whatever shell you are using!

I actually have several alias for ls including

alias ls='ls -FG'
alias ll='ls -lFG'

so thanks for the suggestion — I will add

alias sl='ls -FG'

(Not that I ever remember typing sl but then I tend to us ll or lh!)

1

You could always review it's source code for yourself, and you would see under no condition does it ever perform the actual ls command nor display directories.

https://github.com/mtoyoda/sl

The source is rather simple actually. Even if you are "not a coder" you should still be able to understand most of it.

I believe the "bug" you posted above is really just in jest (and to cause discussion like this lol)

SnakeDoc
  • 492
-1

You could do like I do also...

mv /usr/games/sl /usr/games/sl-OLD

<p>mv /usr/games/LS /usr/games/LS-OLD</p>

<p>nano /usr/games/sl</p>

<blockquote>
  <p>Paste the following:</p>

  <blockquote>
    <p>#!/bin/bash</p>

    <p>echo "YOU TYPED 'sl' INSTEAD OF 'ls'!"</p>

    <p>/usr/games/sl-old</p>

    <p>echo "Guess I can list it anyways..."</p>

    <p>/bin/ls</p>
  </blockquote>
</blockquote>

<p>Press CTRL+X to exit and Y to save.</p>

<p>nano /usr/games/LS</p>

<blockquote>
  <p>Paste the following:</p>

  <blockquote>
    <p>#!/bin/bash</p>

    <p>echo "YOU TYPED 'LS' INSTEAD OF 'ls'!"</p>

    <p>/usr/games/sl-old</p>

    <p>echo "Guess I can list it anyways..."</p>

    <p>/bin/ls</p>
  </blockquote>
</blockquote>

<p>Press CTRL+X to exit and Y to save.</p>

P.S: You're welcome for reviving this.. searching to "sl linux command" still brings this thread up, so I thought I would give a real answer as to how I made it list the files...