Taken straight from Wikipedia:
? The question mark indicates zero or one occurrences of the preceding
element. For example, colou?r matches both "color" and "colour".
* The asterisk indicates zero or more occurrences of the preceding element. For example, ab*c matches "ac", "abc", "abbc", "abbbc", and
so on.
The big difference is that asterisk matches zero or more occurrences, while question mark matches zero or one occurrence. Compare these two examples:
$ printf "colour\ncolor\ncolouur\n" | egrep 'colou?r'
colour
color
$ printf "colour\ncolor\ncolouur\n" | egrep 'colou*r'
colour
color
colouur
Because in colouur
the letter u (the previous element before qualifier ?
) occurred more than once, it's not matched with ?
, but it is matched with *
Similar example:
$ printf "error\neror\ner\n" | egrep 'er?or'
eror
$ printf "error\neror\ner\n" | egrep 'er*or'
error
eror
From the same wikipedia page:
Matches any single character (many applications exclude newlines, and
exactly which characters are considered newlines is flavor-,
character-encoding-, and platform-specific, but it is safe to assume
that the line feed character is included). Within POSIX bracket
expressions, the dot character matches a literal dot. For example, a.c
matches "abc", etc., but [a.c] matches only "a", ".", or "c".
In our example,
$ printf "colour\ncolor\ncolouur\n" | egrep 'colo.r'
colour
$ printf "colour\ncolor\ncolouur\n" | egrep 'colou.r'
colouur
Appropriately enough, the last one reads as match any line that has "colou", plus any character, plus letter "r"
Conclusion
You've asked: "I know that '*' means all or nothing, but I am not sure if it's the right way to think about it. On the other '.' & '?' seem same." As you can see, the dot and asterisk are not exactly the same. The dot operates on any character that may be occupying that specific position, while question mark operates on the preceding element.