The convention is that everything that starts with a
- is an option. This collides with filenames that start with
-. To work around this most commands recognize
-- as an end-of-options sentinel. Everything after the
-- will not be recognized as options, instead will be taken literally as filenames.
cat -- --1
rm -rf -- --1
Another method is to qualify the filename with a path.
Best is to never create filenames that start with
-. Filenames may contain all kinds of characters, including newline, but only because it is possbile doesn't mean you have to do it.
To answer your question: Why cat, grep and other commands can't understand files starting with minus sign? Because the command line is just a string. The shell does some filename expansion and some word splitting and some variable replacement but in the end the program receives an array of strings.
How do you separate the strings which mean options from the strings which mean filenames? By some sentinel characters. The convention in the unix/linux world is to use the
- as the sentinel character. Everything that starts with a
- is an option. Well, almost everything. Arguments to options might also start with
-, but that is detail of the individual program.
Not every program conforms to this convention. Arguably the most popular example is
dd if=/dev/random of=whatfreespace
dd recognizes filenames because they appear after the
Most, if not all, GNU programs conform to the GNU getopt convention: short options start with
- and are only one character, long options start with
-- and are at least two characters.
-- on its own marks the end of options and all strings after that mark are not recognized as options. For more details read Program Argument Syntax Conventions in the GNU libc manual.
One example of a program that only partially conforms to the GNU convention is
find -not -name porn -delete
- to differ options from non options, it does not differ long options from short options. It does recognize
-- as end of options. Every program can define it's own way how to recognize options and filenames and whatever else.
The convention to interpret a single
- as stdin is also just that, a convention of how to interpret the single
- character when it is encountered in the array of strings.