45

There is a thread that talks about ls "*" not showing any files, but I actually wonder why the simple

ls *

command doesn't output anything in my terminal other than

ls: invalid option -- '|'
Try 'ls --help' for more information.

while

ls

will list all the files in the current directories as

 1                  ferol                      readme.txt
 2                  fichier                    sarku
 2018               GameShell                  Templates
 22223333          '-|h4k3r|-'                 test
 3                  hs_err_pid2301.log         test2
 CA.txt             important.top.secret.txt   toto.text
 CA.zip             JavaBlueJProject           tp1_inf1070
 countryInfo.txt    liendur                   'tp1_inf1070_A19(2) (1)'
 currency           liensymbolique             tp1_inf1070_A19.tar
 curreny            LOL                        Videos
 Desktop            Longueuil                 'VirtualBox VMs'
 Documents          Music                      words
 douffos            numbers                    Zip.zip
 Downloads          Pictures
 examples.desktop   Public

Any ideas as to why the globbing doesn't take effect here? I'm on Ubuntu, working in the terminal, I don't know if it makes a difference.

Thanks.

4

4 Answers 4

112

When you run

ls *

globbing takes effect as usual, and the * expands to all filenames in the current directory -- including this one:

-|h4k3r|-

That starts with a -, so ls tries to parse it as an option (like -a or -l). As | isn't actually an option recognized by ls, it complains with the error message invalid option, then exits (without listing any files).

If you want to list everything in the current folder explicitly, instead try

ls ./*

...which will prefix all filenames with ./ (so that entry will not be misinterpreted as an option), or

ls -- *

...where -- is the "delimiter indicating end of options", ie. any remaining arguments are filenames.

17
  • 3
    @rexkogitans : "There is a thread that talks about ls "*" not showing any files" says there is already a thread explaining this and that to do so here is redundant. Commented Oct 25, 2019 at 20:19
  • 8
    @ThomasWeller: The quotes aren't part of the filename; they're only present in the ls listing in the OP because newer versions of GNU ls quote filenames on output when they contain special characters. On the other hand, if you're aware of that and are suggesting that the shell add quotes when expanding a glob, that would go against the decades-old Bourne-shell style; it's not a bug if shell programmers have been working around it for longer than you've been alive.
    – jwodder
    Commented Oct 25, 2019 at 21:08
  • 7
    @jwodder No shell programmer has ever been forced to work around such filenames. Using -- to stop a utility from parsing further arguments as options is a well established way of handling unknown arguments that are not to be considered as options. It's not a hack or a workaround IMHO, just ordinary defensive programming.
    – Kusalananda
    Commented Oct 25, 2019 at 21:13
  • 3
    @jwodder: well, then the bug is that nobody fixed that the first time it was reported as a bug. Well, from now on I'll put -rf files onto every Linux system I find :-) Commented Oct 25, 2019 at 21:13
  • 13
    @jwodder, adding quotes wouldn't help. They only have meaning in the shell. Even if you write ls '-|' (with quotes), ls still sees an argument starting with a dash, and complains about it not being a valid option. On the other hand, if you pass the actual quotes to ls, (as if when running ls "'-|'") then it'll look for a filename containing those quotes, and probably complain that it doesn't exist.
    – ilkkachu
    Commented Oct 25, 2019 at 21:22
4

I think the important missing conceptual leap here is where the globbing is done. ls will never do any globbing itself. If you don't give it any arguments, it assumes you meant . and lists out that directory like it would any directory you gave it on the command line.

The thing that does the globbing is the shell. The shell then passes the results as a bunch of command line arguments to ls. ls has no clue if you typed those arguments, or if they are the result of a glob expansion. And so it parses them for flags like it would any other command line arguments.

This isn't how it works on Windows, which I think is a major flaw in how Windows handles command line programs.

One other interesting demonstration here is to make a directory that has a bunch of directories in it. If you then do ls * there, the shell will give all those directories as arguments, and ls will give you a listing for each of them. This just shows that assuming . if you didn't provide an argument is a simple default, not any kind of special behavior.

If you say ./* instead of * the shell will do a glob expansion that results in everything having ./ in front of it, so ls won't interpret any of the arguments as options. If you do ls -- *, ls interprets the option -- as meaning it should cease trying to process options and treat all the rest of the arguments as files or directories it should give a listing for. So, IMHO, -- is the better choice.

The -- convention is followed by the vast majority of Unix command line utilities and is a standard feature of most argument parsing libraries written for most languages.

9
  • 1
    Is it the Windows behaviour that is a major flaw? Sure, it means that each and every program has to implement globbing itself, while in the unix way, it only has to be implemented in the shell. But doing it in the program shouldn't be much more than a library call, and doing it in the program also avoids exactly the sort of problematic stuff that filenames starting with dashes cause on unixen, and avoids the need to quote the pattern in cases like find -name "*.txt" since the program can now decide what the pattern is applied against.
    – ilkkachu
    Commented Oct 28, 2019 at 4:02
  • 2
    @ilkkachu: The windows way makes it impossible to use quoting to reference a name containing glob characters. Commented Oct 28, 2019 at 4:07
  • @R.., Windows filenames also can't contain the main glob characters (* and ?) or control characters (incl. tab and newline), which also simplifies processing the filenames. Most of the issues with filename handling in shell scripts come from those (and spaces, which is probably the most common case, but forbidding them might be seen as too limiting).
    – ilkkachu
    Commented Oct 28, 2019 at 4:18
  • 4
    @ilkkachu - There are Unix hacks from long ago that relied on no output sanitization by ls and the fact that some terminals could be made to simulate arbitrary user input with control sequences. I always loved that Unix had no senseless limitations on what could be in a filename that existed to support a user space parser implementation. I consider the Unix way better because I can get completely different glob behavior by switching shells if I want and no program cares. It's the correct separation of concerns. Commented Oct 28, 2019 at 4:31
  • 1
    There's also a (longish) study on all the problems with filenames by David Wheeler, here: dwheeler.com/essays/filenames-in-shell.html
    – ilkkachu
    Commented Oct 28, 2019 at 10:16
0

Generally the command ls * should list all the files and directories in your current working directory. There are 2 cases that would lead to the issue you are facing.

  1. If any of the files contained in the Directory have unsupported characters, such as a directory named --2 “or -2 would lead to such an error. For example:

    # ls -la | grep 2$
    drwxrwxr-x  2 test test    4096 Oct 28 14:58 --2
    # ls *
    ls: unrecognized option '--2'
    

    This is because the file name starting with - will be considered as an option to the ls command.

  2. If that’s not the case, I believe that there may be some alias set in your .bashrc file. For example, if I set the alias alias ls='ls –2', I would not be able to use the ls command as it will call for an invalid option which is -2.

1
  • 1
    The hpyhen - character isn't an unsupported character, but as you've noted, one does have to be careful when file/directory names start with one. See the popular answer for reasons and solutions. Commented Oct 28, 2019 at 12:00
-2

It means you have a file named '-|'. Because of the way the shell (bash, ksh, ...) works, all wildcard expressions are evaluated against what is in your current directory before the command is called, so if you have a file called -|, then ls * will be called as ls file1 file2 ... -| ..., and you get this error.

As for how to delete or rename it - you can use mv './-|' xyz to rename it to xyz, for example.

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .