grep filename[asterisk] returns unexpected result

2019-05-26 04:07发布

问题:

I have a basic question about ls command. Suppose in a directory I have 4 files named

run
run1
running
run.sh

So, if i do: ls -l|grep run* then I get no result.

But if i do ls -l|grep run.* then I get run.sh as a result.

However I expected grep to list all of the files in both the cases. Could you make me understand what is going on behind scenes?

回答1:

As long as I understand, the "*" is expanded by the shell before executing the command itself, so your grep will try to catch a string with all the file names! On the other hand, grep expects a regular expression, so the "*" is not interpreted as you expect.

The direct solution would be:

$ ls -l run*

Or, if you want to use grep, then scape the "*" and provide a regular expression:

$ ls -l|grep run.\*
$ ls -l|grep 'run.*'


回答2:

This is because the asterisk is special to the shell and gets expanded. To avoid this, you have to quote the regex for grep to see it unexpanded:

ls -l|grep 'run*'

And note that this is not what you want, because 'run*' as an regexp means 'ru followed by any number of n'. This will list also files named rubber and so on. To list files that match a shell glob pattern (which is different from an regexp), why not simply use

ls -l run*
ls -l run.*

and avoid the useless grep process entirely?



回答3:

Before the shell even runs grep, it searches through your command for any unquoted file globbing characters, and performs filename expansion on those arguments.

So when you enter this command:

ls -l | grep run*

the shell uses the pattern run* to search for files in the current directory, and finds run, run1, running and run.sh. It then rewrites the grep command with those arguments:

ls -l | grep run run1 running run.sh

which causes grep to search run1, running and run.sh for the string run.

As noted, the solution is to quote the argument to grep so the shell does not try to perform filename expansion on it:

ls -l | grep 'run.*'